@metamask/snaps-cli 0.3.1 → 0.6.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 (48) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/README.md +65 -104
  3. package/dist/builders.d.ts +17 -2
  4. package/dist/builders.js +4 -6
  5. package/dist/builders.js.map +1 -1
  6. package/dist/cli.d.ts +0 -7
  7. package/dist/cli.js +3 -3
  8. package/dist/cli.js.map +1 -1
  9. package/dist/cmds/build/buildHandler.js +1 -1
  10. package/dist/cmds/build/buildHandler.js.map +1 -1
  11. package/dist/cmds/build/bundleUtils.d.ts +2 -2
  12. package/dist/cmds/build/bundleUtils.js.map +1 -1
  13. package/dist/cmds/build/index.js +2 -3
  14. package/dist/cmds/build/index.js.map +1 -1
  15. package/dist/cmds/eval/eval-worker.js +4 -1
  16. package/dist/cmds/eval/eval-worker.js.map +1 -1
  17. package/dist/cmds/init/index.js +3 -2
  18. package/dist/cmds/init/index.js.map +1 -1
  19. package/dist/cmds/init/init-template.json +2 -2
  20. package/dist/cmds/init/initHandler.d.ts +6 -1
  21. package/dist/cmds/init/initHandler.js +50 -33
  22. package/dist/cmds/init/initHandler.js.map +1 -1
  23. package/dist/cmds/init/initUtils.d.ts +28 -11
  24. package/dist/cmds/init/initUtils.js +158 -91
  25. package/dist/cmds/init/initUtils.js.map +1 -1
  26. package/dist/cmds/manifest/index.js +3 -6
  27. package/dist/cmds/manifest/index.js.map +1 -1
  28. package/dist/cmds/manifest/manifestHandler.d.ts +15 -3
  29. package/dist/cmds/manifest/manifestHandler.js +180 -147
  30. package/dist/cmds/manifest/manifestHandler.js.map +1 -1
  31. package/dist/cmds/watch/watchHandler.js +2 -0
  32. package/dist/cmds/watch/watchHandler.js.map +1 -1
  33. package/dist/main.js.map +1 -1
  34. package/dist/tsconfig.json +3 -0
  35. package/dist/utils/fs.d.ts +10 -2
  36. package/dist/utils/fs.js +16 -3
  37. package/dist/utils/fs.js.map +1 -1
  38. package/dist/utils/misc.d.ts +4 -3
  39. package/dist/utils/misc.js +24 -4
  40. package/dist/utils/misc.js.map +1 -1
  41. package/dist/utils/readline.d.ts +2 -2
  42. package/dist/utils/readline.js.map +1 -1
  43. package/dist/utils/snap-config.js +12 -17
  44. package/dist/utils/snap-config.js.map +1 -1
  45. package/dist/utils/validate-fs.d.ts +1 -1
  46. package/dist/utils/validate-fs.js +1 -1
  47. package/dist/utils/validate-fs.js.map +1 -1
  48. package/package.json +16 -7
@@ -1,6 +1,18 @@
1
+ import type { SnapManifest } from '@metamask/snap-controllers';
1
2
  import { YargsArgs } from '../../types/yargs';
2
3
  /**
3
- * Validates a Snap package.json file.
4
- * Exits with success message or gathers all errors before throwing at the end.
4
+ * Validates a snap.manifest.json file. Attempts to fix the manifest and write
5
+ * the fixed version to disk if `writeManifest` is true. Throws if validation
6
+ * fails.
7
+ *
8
+ * @param argv - The Yargs `argv` object.
5
9
  */
6
- export declare function manifest(argv: YargsArgs): Promise<void>;
10
+ export declare function manifestHandler({ writeManifest, }: YargsArgs): Promise<void>;
11
+ /**
12
+ * Sorts the given manifest in our preferred sort order and removes the
13
+ * `repository` field if it is falsy (it may be `null`).
14
+ *
15
+ * @param manifest - The manifest to sort and modify.
16
+ * @returns The disk-ready manifest.
17
+ */
18
+ export declare function getWritableManifest(manifest: SnapManifest): SnapManifest;
@@ -1,172 +1,111 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
4
12
  };
5
13
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.manifest = void 0;
14
+ exports.getWritableManifest = exports.manifestHandler = void 0;
7
15
  const fs_1 = require("fs");
8
- const path_1 = __importDefault(require("path"));
9
- const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));
10
- const is_url_1 = __importDefault(require("is-url"));
11
- const rfdc_1 = __importDefault(require("rfdc"));
12
- const utils_1 = require("../../utils");
13
- const deepClone = rfdc_1.default({ proto: false, circles: false });
14
- const LOCALHOST_START = 'http://localhost';
16
+ const utils_1 = require("@metamask/snap-controllers/dist/snaps/utils");
17
+ const utils_2 = require("../../utils");
18
+ const errorPrefix = 'Manifest Error: ';
19
+ const ManifestSortOrder = {
20
+ version: 1,
21
+ proposedName: 2,
22
+ description: 2,
23
+ repository: 3,
24
+ source: 4,
25
+ initialPermissions: 5,
26
+ manifestVersion: 6,
27
+ };
15
28
  /**
16
- * Validates a Snap package.json file.
17
- * Exits with success message or gathers all errors before throwing at the end.
29
+ * Validates a snap.manifest.json file. Attempts to fix the manifest and write
30
+ * the fixed version to disk if `writeManifest` is true. Throws if validation
31
+ * fails.
32
+ *
33
+ * @param argv - The Yargs `argv` object.
18
34
  */
19
- async function manifest(argv) {
20
- let isInvalid = false;
21
- let hasWarnings = false;
35
+ async function manifestHandler({ writeManifest, }) {
36
+ var _a, _b, _c;
22
37
  let didUpdate = false;
23
- const { dist, port, outfileName } = argv;
24
- if (!dist) {
25
- throw new Error(`Invalid params: must provide 'dist'`);
26
- }
27
- // read the package.json file
28
- let pkg;
38
+ let hasWarnings = false;
39
+ const unvalidatedManifest = await readSnapJsonFile(utils_1.NpmSnapFileNames.Manifest);
40
+ const iconPath = unvalidatedManifest && typeof unvalidatedManifest === 'object'
41
+ ? (_c = (_b = (_a = unvalidatedManifest.source) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.npm) === null || _c === void 0 ? void 0 : _c.iconPath
42
+ : undefined;
43
+ const snapFiles = {
44
+ manifest: unvalidatedManifest,
45
+ packageJson: await readSnapJsonFile(utils_1.NpmSnapFileNames.PackageJson),
46
+ sourceCode: await getSnapSourceCode(unvalidatedManifest),
47
+ svgIcon: iconPath && (await fs_1.promises.readFile(iconPath, 'utf8')),
48
+ };
49
+ let manifest;
29
50
  try {
30
- pkg = JSON.parse(await fs_1.promises.readFile('package.json', 'utf-8'));
31
- }
32
- catch (err) {
33
- if (err.code === 'ENOENT') {
34
- throw new Error(`Manifest error: Could not find package.json. Please ensure that ` +
35
- `you are running the command in the project root directory.`);
36
- }
37
- throw new Error(`Could not parse package.json`);
38
- }
39
- if (!pkg || typeof pkg !== 'object') {
40
- throw new Error(`Invalid parsed package.json: ${pkg}`);
51
+ ({ manifest } = utils_1.validateNpmSnap(snapFiles, errorPrefix));
41
52
  }
42
- // attempt to set missing/erroneous properties if commanded
43
- if (argv.populate) {
44
- const old = pkg.web3Wallet ? deepClone(pkg.web3Wallet) : {};
45
- if (!pkg.web3Wallet) {
46
- pkg.web3Wallet = {};
47
- }
48
- const bundle = pkg.web3Wallet.bundle || {};
49
- if (!pkg.web3Wallet.bundle) {
50
- pkg.web3Wallet.bundle = bundle;
51
- }
52
- if (!pkg.web3Wallet.initialPermissions) {
53
- pkg.web3Wallet.initialPermissions = {};
54
- }
55
- const { web3Wallet } = pkg;
56
- const bundlePath = path_1.default.join(dist, outfileName || 'bundle.js');
57
- if (bundle.local !== bundlePath) {
58
- bundle.local = bundlePath;
59
- }
60
- if (port &&
61
- (typeof bundle.url !== 'string' || bundle.url.startsWith(LOCALHOST_START))) {
62
- bundle.url = `${LOCALHOST_START}:${port}/${bundlePath}`;
63
- }
64
- // sort web3Wallet object keys
65
- Object.keys(web3Wallet)
66
- .sort()
67
- .forEach((_key) => {
68
- const key = _key;
69
- const property = web3Wallet[key];
70
- if (property &&
71
- typeof property === 'object' &&
72
- !Array.isArray(property)) {
73
- web3Wallet[key] = Object.keys(property)
74
- .sort()
75
- .reduce((sortedProperty, _innerKey) => {
76
- const innerKey = _innerKey;
77
- sortedProperty[innerKey] = property[innerKey];
78
- return sortedProperty;
79
- }, {});
53
+ catch (error) {
54
+ if (writeManifest && error instanceof utils_1.ProgrammaticallyFixableSnapError) {
55
+ // If we get here, the files at least have the correct shape.
56
+ const partiallyValidatedFiles = snapFiles;
57
+ let isInvalid = true;
58
+ const maxAttempts = Object.keys(utils_1.SnapValidationFailureReason).length;
59
+ // Attempt to fix all fixable validation failure reasons. All such reasons
60
+ // are enumerated by the SnapValidationFailureReason enum, so we only
61
+ for (let attempts = 1; isInvalid && attempts <= maxAttempts; attempts++) {
62
+ manifest = fixManifest(partiallyValidatedFiles, error);
63
+ try {
64
+ utils_1.validateNpmSnapManifest(Object.assign(Object.assign({}, partiallyValidatedFiles), { manifest }), errorPrefix);
65
+ isInvalid = false;
66
+ }
67
+ catch (nextValidationError) {
68
+ /* istanbul ignore next: this should be impossible */
69
+ if (!(nextValidationError instanceof utils_1.ProgrammaticallyFixableSnapError) ||
70
+ (attempts === maxAttempts && !isInvalid)) {
71
+ throw new Error(`Internal Error: Failed to fix manifest. This is a bug, please report it. Reason:\n${error.message}`);
72
+ }
73
+ }
80
74
  }
81
- });
82
- if (!fast_deep_equal_1.default(old, web3Wallet)) {
83
75
  didUpdate = true;
84
76
  }
85
- }
86
- // check presence of required and recommended keys
87
- const existing = Object.keys(pkg);
88
- const required = ['name', 'version', 'description', 'main', 'web3Wallet'];
89
- const recommended = ['repository'];
90
- let missing = required.filter((key) => !existing.includes(key));
91
- if (missing.length > 0) {
92
- logManifestWarning(`Missing required package.json properties:\n${missing.reduce((acc, curr) => {
93
- return `${acc}\t${curr}\n`;
94
- }, '')}`);
95
- }
96
- missing = recommended.filter((key) => !existing.includes(key));
97
- if (missing.length > 0) {
98
- logManifestWarning(`Missing recommended package.json properties:\n${missing.reduce((acc, curr) => {
99
- return `${acc}\t${curr}\n`;
100
- }, '')}`);
101
- }
102
- // check web3Wallet properties
103
- if (pkg.web3Wallet !== undefined) {
104
- const { bundle, initialPermissions } = pkg.web3Wallet || {};
105
- if (bundle === null || bundle === void 0 ? void 0 : bundle.local) {
106
- if (!(await utils_1.isFile(bundle.local))) {
107
- logManifestError(`'bundle.local' does not resolve to a file.`);
108
- }
109
- }
110
77
  else {
111
- logManifestError(`Missing required 'web3Wallet' property 'bundle.local'.`);
112
- }
113
- if (bundle !== undefined) {
114
- if (!bundle.url) {
115
- logManifestError(`Missing required 'bundle.url' property.`);
116
- }
117
- else if (!is_url_1.default(bundle.url)) {
118
- logManifestError(`'bundle.url' does not resolve to a URL.`);
119
- }
120
- }
121
- if (Object.prototype.hasOwnProperty.call(pkg.web3Wallet, 'initialPermissions')) {
122
- if (typeof initialPermissions !== 'object' ||
123
- Array.isArray(initialPermissions)) {
124
- logManifestError(`'web3Wallet' property 'initialPermissions' must be an object if present.`);
125
- }
126
- else if (Object.keys(initialPermissions).length > 0) {
127
- Object.entries(initialPermissions).forEach(([permission, value]) => {
128
- if (typeof value !== 'object' || Array.isArray(value)) {
129
- logManifestError(`initial permission '${permission}' must be an object`);
130
- }
131
- else if (value !== null) {
132
- Object.keys(value).forEach((permissionKey) => {
133
- if (!utils_1.permRequestKeys.includes(permissionKey)) {
134
- logManifestError(`initial permission '${permission}' has unrecognized key '${permissionKey}'`);
135
- }
136
- if (permissionKey === 'parentCapability' &&
137
- permission !== permissionKey) {
138
- logManifestError(`initial permission '${permission}' has mismatched 'parentCapability' field '${value[permissionKey]}'`);
139
- }
140
- });
141
- }
142
- });
143
- }
78
+ throw error;
144
79
  }
145
80
  }
146
- // validation complete, finish work and notify user
147
- if (argv.populate) {
81
+ // TypeScript doesn't see that the 'manifest' variable must be of type
82
+ // SnapManifest at this point, so we cast it.
83
+ const validatedManifest = manifest;
84
+ // Check presence of recommended keys
85
+ const recommendedFields = ['repository'];
86
+ const missingRecommendedFields = recommendedFields.filter((key) => !validatedManifest[key]);
87
+ if (missingRecommendedFields.length > 0) {
88
+ logManifestWarning(`Missing recommended package.json properties:\n${missingRecommendedFields.reduce((allMissing, currentField) => {
89
+ return `${allMissing}\t${currentField}\n`;
90
+ }, '')}`);
91
+ }
92
+ // Validation complete, finish work and notify user.
93
+ if (writeManifest) {
148
94
  try {
149
- await fs_1.promises.writeFile('package.json', `${JSON.stringify(pkg, null, 2)}\n`);
95
+ await fs_1.promises.writeFile(utils_1.NpmSnapFileNames.Manifest, `${JSON.stringify(getWritableManifest(validatedManifest), null, 2)}\n`);
150
96
  if (didUpdate) {
151
- console.log(`Manifest: Updated '${pkg.name}' package.json!`);
97
+ console.log(`Manifest: Updated snap.manifest.json`);
152
98
  }
153
99
  }
154
- catch (err) {
155
- throw new Error(`Could not write package.json`);
100
+ catch (error) {
101
+ throw new Error(`${errorPrefix}Failed to update snap.manifest.json: ${error.message}`);
156
102
  }
157
103
  }
158
- if (isInvalid) {
159
- throw new Error(`Manifest Error: package.json validation failed, please see above errors.`);
160
- }
161
- else if (hasWarnings) {
162
- console.log(`Manifest Warning: Validation of '${pkg.name}' package.json completed with warnings. See above.`);
104
+ if (hasWarnings) {
105
+ console.log(`Manifest Warning: Validation of snap.manifest.json completed with warnings. See above.`);
163
106
  }
164
107
  else {
165
- console.log(`Manifest Success: Validated '${pkg.name}' package.json!`);
166
- }
167
- function logManifestError(message) {
168
- isInvalid = true;
169
- console.error(`Manifest Error: ${message}`);
108
+ console.log(`Manifest Success: Validated snap.manifest.json!`);
170
109
  }
171
110
  function logManifestWarning(message) {
172
111
  if (!global.snaps.suppressWarnings) {
@@ -175,5 +114,99 @@ async function manifest(argv) {
175
114
  }
176
115
  }
177
116
  }
178
- exports.manifest = manifest;
117
+ exports.manifestHandler = manifestHandler;
118
+ /**
119
+ * Utility function for reading `package.json` or the Snap manifest file.
120
+ * These are assumed to be in the current working directory.
121
+ *
122
+ * @param snapJsonFileName - The name of the file to read.
123
+ * @returns The parsed JSON file.
124
+ */
125
+ async function readSnapJsonFile(snapJsonFileName) {
126
+ try {
127
+ return await utils_2.readJsonFile(snapJsonFileName);
128
+ }
129
+ catch (error) {
130
+ if (error.code === 'ENOENT') {
131
+ throw new Error(`${errorPrefix}Could not find '${snapJsonFileName}'. Please ensure that ` +
132
+ `you are running the command in the project root directory.`);
133
+ }
134
+ throw new Error(`${errorPrefix}${error.message}`);
135
+ }
136
+ }
137
+ /**
138
+ * Given an unvalidated Snap manifest, attempts to extract the location of the
139
+ * bundle source file location and read the file.
140
+ *
141
+ * @param manifest - The unvalidated Snap manifest file contents.
142
+ * @returns The contents of the bundle file, if any.
143
+ */
144
+ async function getSnapSourceCode(manifest) {
145
+ var _a, _b, _c;
146
+ if (manifest && typeof manifest === 'object' && !Array.isArray(manifest)) {
147
+ /* istanbul ignore next: optional chaining */
148
+ const sourceFilePath = (_c = (_b = (_a = manifest.source) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.npm) === null || _c === void 0 ? void 0 : _c.filePath;
149
+ try {
150
+ return sourceFilePath
151
+ ? await fs_1.promises.readFile(sourceFilePath, 'utf8')
152
+ : undefined;
153
+ }
154
+ catch (error) {
155
+ throw new Error(`Manifest Error: Failed to read Snap bundle file: ${error.message}`);
156
+ }
157
+ }
158
+ return undefined;
159
+ }
160
+ /**
161
+ * Given the relevant Snap files (manifest, `package.json`, and bundle) and a
162
+ * Snap manifest validation error, fixes the fault in the manifest that caused
163
+ * the error.
164
+ *
165
+ * @param snapFiles - The contents of all Snap files.
166
+ * @param error - The {@link ProgrammaticallyFixableSnapError} that was thrown.
167
+ * @returns A copy of the manifest file where the cause of the error is fixed.
168
+ */
169
+ function fixManifest(snapFiles, error) {
170
+ const { manifest, packageJson, sourceCode } = snapFiles;
171
+ const manifestCopy = utils_2.deepClone(manifest);
172
+ switch (error.reason) {
173
+ case utils_1.SnapValidationFailureReason.NameMismatch:
174
+ manifestCopy.source.location.npm.packageName = packageJson.name;
175
+ break;
176
+ case utils_1.SnapValidationFailureReason.VersionMismatch:
177
+ manifestCopy.version = packageJson.version;
178
+ break;
179
+ case utils_1.SnapValidationFailureReason.RepositoryMismatch:
180
+ manifestCopy.repository = packageJson.repository
181
+ ? utils_2.deepClone(packageJson.repository)
182
+ : null;
183
+ break;
184
+ case utils_1.SnapValidationFailureReason.ShasumMismatch:
185
+ manifestCopy.source.shasum = utils_1.getSnapSourceShasum(sourceCode);
186
+ break;
187
+ /* istanbul ignore next */
188
+ default:
189
+ // eslint-disable-next-line no-case-declarations
190
+ const failureReason = error.reason;
191
+ throw new Error(`Unrecognized validation failure reason: '${failureReason}'`);
192
+ }
193
+ return manifestCopy;
194
+ }
195
+ /**
196
+ * Sorts the given manifest in our preferred sort order and removes the
197
+ * `repository` field if it is falsy (it may be `null`).
198
+ *
199
+ * @param manifest - The manifest to sort and modify.
200
+ * @returns The disk-ready manifest.
201
+ */
202
+ function getWritableManifest(manifest) {
203
+ const { repository } = manifest, remaining = __rest(manifest, ["repository"]);
204
+ return Object.keys(repository ? Object.assign(Object.assign({}, remaining), { repository }) : remaining)
205
+ .sort((a, b) => ManifestSortOrder[a] - ManifestSortOrder[b])
206
+ .reduce((outManifest, key) => {
207
+ outManifest[key] = manifest[key];
208
+ return outManifest;
209
+ }, {});
210
+ }
211
+ exports.getWritableManifest = getWritableManifest;
179
212
  //# sourceMappingURL=manifestHandler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"manifestHandler.js","sourceRoot":"","sources":["../../../src/cmds/manifest/manifestHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'fs';\nimport pathUtils from 'path';\nimport dequal from 'fast-deep-equal';\nimport isUrl from 'is-url';\nimport rfdc from 'rfdc';\nimport { isFile, permRequestKeys } from '../../utils';\nimport { YargsArgs } from '../../types/yargs';\nimport {\n NodePackageManifest,\n ManifestWalletProperty,\n} from '../../types/package';\n\nconst deepClone = rfdc({ proto: false, circles: false });\n\nconst LOCALHOST_START = 'http://localhost';\n\n/**\n * Validates a Snap package.json file.\n * Exits with success message or gathers all errors before throwing at the end.\n */\nexport async function manifest(argv: YargsArgs): Promise<void> {\n let isInvalid = false;\n let hasWarnings = false;\n let didUpdate = false;\n\n const { dist, port, outfileName } = argv;\n if (!dist) {\n throw new Error(`Invalid params: must provide 'dist'`);\n }\n\n // read the package.json file\n let pkg: NodePackageManifest;\n try {\n pkg = JSON.parse(await fs.readFile('package.json', 'utf-8'));\n } catch (err) {\n if (err.code === 'ENOENT') {\n throw new Error(\n `Manifest error: Could not find package.json. Please ensure that ` +\n `you are running the command in the project root directory.`,\n );\n }\n throw new Error(`Could not parse package.json`);\n }\n\n if (!pkg || typeof pkg !== 'object') {\n throw new Error(`Invalid parsed package.json: ${pkg}`);\n }\n\n // attempt to set missing/erroneous properties if commanded\n if (argv.populate) {\n const old = pkg.web3Wallet ? deepClone(pkg.web3Wallet) : {};\n\n if (!pkg.web3Wallet) {\n pkg.web3Wallet = {};\n }\n\n const bundle = pkg.web3Wallet.bundle || {};\n if (!pkg.web3Wallet.bundle) {\n pkg.web3Wallet.bundle = bundle;\n }\n\n if (!pkg.web3Wallet.initialPermissions) {\n pkg.web3Wallet.initialPermissions = {};\n }\n\n const { web3Wallet } = pkg;\n\n const bundlePath = pathUtils.join(\n dist,\n (outfileName as string) || 'bundle.js',\n );\n if (bundle.local !== bundlePath) {\n bundle.local = bundlePath;\n }\n\n if (\n port &&\n (typeof bundle.url !== 'string' || bundle.url.startsWith(LOCALHOST_START))\n ) {\n bundle.url = `${LOCALHOST_START}:${port}/${bundlePath}`;\n }\n\n // sort web3Wallet object keys\n Object.keys(web3Wallet)\n .sort()\n .forEach((_key) => {\n const key = _key as keyof ManifestWalletProperty;\n const property = web3Wallet[key];\n\n if (\n property &&\n typeof property === 'object' &&\n !Array.isArray(property)\n ) {\n web3Wallet[key] = Object.keys(property)\n .sort()\n .reduce((sortedProperty, _innerKey) => {\n const innerKey =\n _innerKey as keyof ManifestWalletProperty[typeof key];\n sortedProperty[innerKey] = property[innerKey];\n\n return sortedProperty;\n }, {} as Record<string, unknown>);\n }\n });\n\n if (!dequal(old, web3Wallet)) {\n didUpdate = true;\n }\n }\n\n // check presence of required and recommended keys\n const existing = Object.keys(pkg);\n const required = ['name', 'version', 'description', 'main', 'web3Wallet'];\n const recommended = ['repository'];\n\n let missing = required.filter((key) => !existing.includes(key));\n if (missing.length > 0) {\n logManifestWarning(\n `Missing required package.json properties:\\n${missing.reduce(\n (acc, curr) => {\n return `${acc}\\t${curr}\\n`;\n },\n '',\n )}`,\n );\n }\n\n missing = recommended.filter((key) => !existing.includes(key));\n if (missing.length > 0) {\n logManifestWarning(\n `Missing recommended package.json properties:\\n${missing.reduce(\n (acc, curr) => {\n return `${acc}\\t${curr}\\n`;\n },\n '',\n )}`,\n );\n }\n\n // check web3Wallet properties\n if (pkg.web3Wallet !== undefined) {\n const { bundle, initialPermissions } = pkg.web3Wallet || {};\n if (bundle?.local) {\n if (!(await isFile(bundle.local))) {\n logManifestError(`'bundle.local' does not resolve to a file.`);\n }\n } else {\n logManifestError(\n `Missing required 'web3Wallet' property 'bundle.local'.`,\n );\n }\n\n if (bundle !== undefined) {\n if (!bundle.url) {\n logManifestError(`Missing required 'bundle.url' property.`);\n } else if (!isUrl(bundle.url)) {\n logManifestError(`'bundle.url' does not resolve to a URL.`);\n }\n }\n\n if (\n Object.prototype.hasOwnProperty.call(pkg.web3Wallet, 'initialPermissions')\n ) {\n if (\n typeof initialPermissions !== 'object' ||\n Array.isArray(initialPermissions)\n ) {\n logManifestError(\n `'web3Wallet' property 'initialPermissions' must be an object if present.`,\n );\n } else if (Object.keys(initialPermissions).length > 0) {\n Object.entries(initialPermissions).forEach(([permission, value]) => {\n if (typeof value !== 'object' || Array.isArray(value)) {\n logManifestError(\n `initial permission '${permission}' must be an object`,\n );\n } else if (value !== null) {\n Object.keys(value).forEach((permissionKey) => {\n if (!permRequestKeys.includes(permissionKey)) {\n logManifestError(\n `initial permission '${permission}' has unrecognized key '${permissionKey}'`,\n );\n }\n\n if (\n permissionKey === 'parentCapability' &&\n permission !== permissionKey\n ) {\n logManifestError(\n `initial permission '${permission}' has mismatched 'parentCapability' field '${\n (value as Record<string, unknown>)[permissionKey]\n }'`,\n );\n }\n });\n }\n });\n }\n }\n }\n\n // validation complete, finish work and notify user\n\n if (argv.populate) {\n try {\n await fs.writeFile('package.json', `${JSON.stringify(pkg, null, 2)}\\n`);\n if (didUpdate) {\n console.log(`Manifest: Updated '${pkg.name}' package.json!`);\n }\n } catch (err) {\n throw new Error(`Could not write package.json`);\n }\n }\n\n if (isInvalid) {\n throw new Error(\n `Manifest Error: package.json validation failed, please see above errors.`,\n );\n } else if (hasWarnings) {\n console.log(\n `Manifest Warning: Validation of '${pkg.name}' package.json completed with warnings. See above.`,\n );\n } else {\n console.log(`Manifest Success: Validated '${pkg.name}' package.json!`);\n }\n\n function logManifestError(message: string) {\n isInvalid = true;\n console.error(`Manifest Error: ${message}`);\n }\n\n function logManifestWarning(message: string) {\n if (!global.snaps.suppressWarnings) {\n hasWarnings = true;\n console.warn(`Manifest Warning: ${message}`);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"manifestHandler.js","sourceRoot":"","sources":["../../../src/cmds/manifest/manifestHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'fs';\nimport type { Json, SnapManifest } from '@metamask/snap-controllers';\nimport {\n NpmSnapFileNames,\n UnvalidatedSnapFiles,\n validateNpmSnap,\n validateNpmSnapManifest,\n getSnapSourceShasum,\n ProgrammaticallyFixableSnapError,\n SnapValidationFailureReason,\n SnapFiles,\n} from '@metamask/snap-controllers/dist/snaps/utils';\nimport { deepClone, readJsonFile } from '../../utils';\nimport { YargsArgs } from '../../types/yargs';\n\nconst errorPrefix = 'Manifest Error: ';\n\nconst ManifestSortOrder: Record<keyof SnapManifest, number> = {\n version: 1,\n proposedName: 2,\n description: 2,\n repository: 3,\n source: 4,\n initialPermissions: 5,\n manifestVersion: 6,\n};\n\n/**\n * Validates a snap.manifest.json file. Attempts to fix the manifest and write\n * the fixed version to disk if `writeManifest` is true. Throws if validation\n * fails.\n *\n * @param argv - The Yargs `argv` object.\n */\nexport async function manifestHandler({\n writeManifest,\n}: YargsArgs): Promise<void> {\n let didUpdate = false;\n let hasWarnings = false;\n\n const unvalidatedManifest = await readSnapJsonFile(NpmSnapFileNames.Manifest);\n\n const iconPath =\n unvalidatedManifest && typeof unvalidatedManifest === 'object'\n ? (unvalidatedManifest as Partial<SnapManifest>).source?.location?.npm\n ?.iconPath\n : undefined;\n\n const snapFiles: UnvalidatedSnapFiles = {\n manifest: unvalidatedManifest,\n packageJson: await readSnapJsonFile(NpmSnapFileNames.PackageJson),\n sourceCode: await getSnapSourceCode(unvalidatedManifest),\n svgIcon: iconPath && (await fs.readFile(iconPath, 'utf8')),\n };\n\n let manifest: SnapManifest | undefined;\n try {\n ({ manifest } = validateNpmSnap(snapFiles, errorPrefix));\n } catch (error) {\n if (writeManifest && error instanceof ProgrammaticallyFixableSnapError) {\n // If we get here, the files at least have the correct shape.\n const partiallyValidatedFiles = snapFiles as SnapFiles;\n\n let isInvalid = true;\n const maxAttempts = Object.keys(SnapValidationFailureReason).length;\n\n // Attempt to fix all fixable validation failure reasons. All such reasons\n // are enumerated by the SnapValidationFailureReason enum, so we only\n for (let attempts = 1; isInvalid && attempts <= maxAttempts; attempts++) {\n manifest = fixManifest(partiallyValidatedFiles, error);\n\n try {\n validateNpmSnapManifest(\n { ...partiallyValidatedFiles, manifest },\n errorPrefix,\n );\n\n isInvalid = false;\n } catch (nextValidationError) {\n /* istanbul ignore next: this should be impossible */\n if (\n !(\n nextValidationError instanceof ProgrammaticallyFixableSnapError\n ) ||\n (attempts === maxAttempts && !isInvalid)\n ) {\n throw new Error(\n `Internal Error: Failed to fix manifest. This is a bug, please report it. Reason:\\n${error.message}`,\n );\n }\n }\n }\n\n didUpdate = true;\n } else {\n throw error;\n }\n }\n\n // TypeScript doesn't see that the 'manifest' variable must be of type\n // SnapManifest at this point, so we cast it.\n const validatedManifest = manifest as SnapManifest;\n\n // Check presence of recommended keys\n const recommendedFields = ['repository'] as const;\n\n const missingRecommendedFields = recommendedFields.filter(\n (key) => !validatedManifest[key],\n );\n\n if (missingRecommendedFields.length > 0) {\n logManifestWarning(\n `Missing recommended package.json properties:\\n${missingRecommendedFields.reduce(\n (allMissing, currentField) => {\n return `${allMissing}\\t${currentField}\\n`;\n },\n '',\n )}`,\n );\n }\n\n // Validation complete, finish work and notify user.\n\n if (writeManifest) {\n try {\n await fs.writeFile(\n NpmSnapFileNames.Manifest,\n `${JSON.stringify(getWritableManifest(validatedManifest), null, 2)}\\n`,\n );\n\n if (didUpdate) {\n console.log(`Manifest: Updated snap.manifest.json`);\n }\n } catch (error) {\n throw new Error(\n `${errorPrefix}Failed to update snap.manifest.json: ${error.message}`,\n );\n }\n }\n\n if (hasWarnings) {\n console.log(\n `Manifest Warning: Validation of snap.manifest.json completed with warnings. See above.`,\n );\n } else {\n console.log(`Manifest Success: Validated snap.manifest.json!`);\n }\n\n function logManifestWarning(message: string) {\n if (!global.snaps.suppressWarnings) {\n hasWarnings = true;\n console.warn(`Manifest Warning: ${message}`);\n }\n }\n}\n\n/**\n * Utility function for reading `package.json` or the Snap manifest file.\n * These are assumed to be in the current working directory.\n *\n * @param snapJsonFileName - The name of the file to read.\n * @returns The parsed JSON file.\n */\nasync function readSnapJsonFile(\n snapJsonFileName: NpmSnapFileNames,\n): Promise<Json> {\n try {\n return await readJsonFile(snapJsonFileName);\n } catch (error) {\n if (error.code === 'ENOENT') {\n throw new Error(\n `${errorPrefix}Could not find '${snapJsonFileName}'. Please ensure that ` +\n `you are running the command in the project root directory.`,\n );\n }\n throw new Error(`${errorPrefix}${error.message}`);\n }\n}\n\n/**\n * Given an unvalidated Snap manifest, attempts to extract the location of the\n * bundle source file location and read the file.\n *\n * @param manifest - The unvalidated Snap manifest file contents.\n * @returns The contents of the bundle file, if any.\n */\nasync function getSnapSourceCode(manifest: Json): Promise<string | undefined> {\n if (manifest && typeof manifest === 'object' && !Array.isArray(manifest)) {\n /* istanbul ignore next: optional chaining */\n const sourceFilePath = (manifest as Partial<SnapManifest>).source?.location\n ?.npm?.filePath;\n\n try {\n return sourceFilePath\n ? await fs.readFile(sourceFilePath, 'utf8')\n : undefined;\n } catch (error) {\n throw new Error(\n `Manifest Error: Failed to read Snap bundle file: ${error.message}`,\n );\n }\n }\n return undefined;\n}\n\n/**\n * Given the relevant Snap files (manifest, `package.json`, and bundle) and a\n * Snap manifest validation error, fixes the fault in the manifest that caused\n * the error.\n *\n * @param snapFiles - The contents of all Snap files.\n * @param error - The {@link ProgrammaticallyFixableSnapError} that was thrown.\n * @returns A copy of the manifest file where the cause of the error is fixed.\n */\nfunction fixManifest(\n snapFiles: SnapFiles,\n error: ProgrammaticallyFixableSnapError,\n): SnapManifest {\n const { manifest, packageJson, sourceCode } = snapFiles;\n const manifestCopy = deepClone(manifest);\n\n switch (error.reason) {\n case SnapValidationFailureReason.NameMismatch:\n manifestCopy.source.location.npm.packageName = packageJson.name;\n break;\n\n case SnapValidationFailureReason.VersionMismatch:\n manifestCopy.version = packageJson.version;\n break;\n\n case SnapValidationFailureReason.RepositoryMismatch:\n manifestCopy.repository = packageJson.repository\n ? deepClone(packageJson.repository)\n : null;\n break;\n\n case SnapValidationFailureReason.ShasumMismatch:\n manifestCopy.source.shasum = getSnapSourceShasum(sourceCode);\n break;\n\n /* istanbul ignore next */\n default:\n // eslint-disable-next-line no-case-declarations\n const failureReason: never = error.reason;\n throw new Error(\n `Unrecognized validation failure reason: '${failureReason}'`,\n );\n }\n\n return manifestCopy;\n}\n\n/**\n * Sorts the given manifest in our preferred sort order and removes the\n * `repository` field if it is falsy (it may be `null`).\n *\n * @param manifest - The manifest to sort and modify.\n * @returns The disk-ready manifest.\n */\nexport function getWritableManifest(manifest: SnapManifest): SnapManifest {\n const { repository, ...remaining } = manifest;\n return (\n Object.keys(\n repository ? { ...remaining, repository } : remaining,\n ) as (keyof SnapManifest)[]\n )\n .sort((a, b) => ManifestSortOrder[a] - ManifestSortOrder[b])\n .reduce((outManifest, key) => {\n (outManifest as any)[key] = manifest[key];\n return outManifest;\n }, {} as SnapManifest);\n}\n"]}
@@ -35,6 +35,8 @@ async function watch(argv) {
35
35
  `**/${dist}/**`,
36
36
  `**/test/**`,
37
37
  `**/tests/**`,
38
+ `**/*.test.js`,
39
+ `**/*.test.ts`,
38
40
  /* istanbul ignore next */
39
41
  (str) => str !== '.' && str.startsWith('.'),
40
42
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"watchHandler.js","sourceRoot":"","sources":["../../../src/cmds/watch/watchHandler.ts"],"names":[],"mappings":";;;;;;AAAA,wDAAgC;AAEhC,4CAAyC;AACzC,uCAMqB;AAErB;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,KAAK,CAAC,IAAe;IACzC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IACxC,IAAI,WAAW,EAAE;QACf,2BAAmB,CAAC,WAAqB,CAAC,CAAC;KAC5C;IACD,MAAM,wBAAgB,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,uBAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAClC,MAAM,OAAO,GACX,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7E,MAAM,WAAW,GAAG,sBAAc,CAAC,IAAI,EAAE,WAAqB,CAAC,CAAC;IAEhE,MAAM,OAAO,GAAG,kBAAQ,CAAC,KAAK,CAAC,OAAO,EAAE;QACtC,aAAa,EAAE,IAAI;QACnB,OAAO,EAAE;YACP,oBAAoB;YACpB,MAAM,IAAI,KAAK;YACf,YAAY;YACZ,aAAa;YACb,0BAA0B;YAC1B,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;SACpD;KACF,CAAC,CAAC;IAEH,OAAO;SACJ,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAChB,eAAM,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC,CAAC;SACD,EAAE,CAAC,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE;QAC1B,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC;QACnC,eAAM,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC,CAAC;SACD,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAY,EAAE,EAAE;QAC7B,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;QACrC,eAAM,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC,CAAC;SACD,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;SACpE,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;QAC1B,gBAAQ,CAAC,kBAAkB,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEL,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,EAAE,CAAC,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,aAAa,OAAO,kBAAkB,CAAC,CAAC;AACtD,CAAC;AA1CD,sBA0CC","sourcesContent":["import chokidar from 'chokidar';\nimport { YargsArgs } from '../../types/yargs';\nimport { bundle } from '../build/bundle';\nimport {\n logError,\n getOutfilePath,\n validateDirPath,\n validateFilePath,\n validateOutfileName,\n} from '../../utils';\n\n/**\n * Watch a directory and its subdirectories for changes, and build when files\n * are added or changed.\n *\n * Ignores 'node_modules' and dotfiles.\n * Creates destination directory if it doesn't exist.\n *\n * @param argv - arguments as an object generated by yargs\n * @param argv.src - The source file path\n * @param argv.dist - The output directory path\n * @param argv.'outfileName' - The output file name\n */\nexport async function watch(argv: YargsArgs): Promise<void> {\n const { src, dist, outfileName } = argv;\n if (outfileName) {\n validateOutfileName(outfileName as string);\n }\n await validateFilePath(src);\n await validateDirPath(dist, true);\n const rootDir =\n src.indexOf('/') === -1 ? '.' : src.substring(0, src.lastIndexOf('/') + 1);\n const outfilePath = getOutfilePath(dist, outfileName as string);\n\n const watcher = chokidar.watch(rootDir, {\n ignoreInitial: true,\n ignored: [\n '**/node_modules/**',\n `**/${dist}/**`,\n `**/test/**`,\n `**/tests/**`,\n /* istanbul ignore next */\n (str: string) => str !== '.' && str.startsWith('.'),\n ],\n });\n\n watcher\n .on('ready', () => {\n bundle(src, outfilePath, argv);\n })\n .on('add', (path: string) => {\n console.log(`File added: ${path}`);\n bundle(src, outfilePath, argv);\n })\n .on('change', (path: string) => {\n console.log(`File changed: ${path}`);\n bundle(src, outfilePath, argv);\n })\n .on('unlink', (path: string) => console.log(`File removed: ${path}`))\n .on('error', (err: Error) => {\n logError(`Watcher error: ${err.message}`, err);\n });\n\n watcher.add(`${rootDir}`);\n console.log(`Watching '${rootDir}' for changes...`);\n}\n"]}
1
+ {"version":3,"file":"watchHandler.js","sourceRoot":"","sources":["../../../src/cmds/watch/watchHandler.ts"],"names":[],"mappings":";;;;;;AAAA,wDAAgC;AAEhC,4CAAyC;AACzC,uCAMqB;AAErB;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,KAAK,CAAC,IAAe;IACzC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IACxC,IAAI,WAAW,EAAE;QACf,2BAAmB,CAAC,WAAqB,CAAC,CAAC;KAC5C;IACD,MAAM,wBAAgB,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,uBAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAClC,MAAM,OAAO,GACX,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7E,MAAM,WAAW,GAAG,sBAAc,CAAC,IAAI,EAAE,WAAqB,CAAC,CAAC;IAEhE,MAAM,OAAO,GAAG,kBAAQ,CAAC,KAAK,CAAC,OAAO,EAAE;QACtC,aAAa,EAAE,IAAI;QACnB,OAAO,EAAE;YACP,oBAAoB;YACpB,MAAM,IAAI,KAAK;YACf,YAAY;YACZ,aAAa;YACb,cAAc;YACd,cAAc;YACd,0BAA0B;YAC1B,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;SACpD;KACF,CAAC,CAAC;IAEH,OAAO;SACJ,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAChB,eAAM,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC,CAAC;SACD,EAAE,CAAC,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE;QAC1B,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC;QACnC,eAAM,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC,CAAC;SACD,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAY,EAAE,EAAE;QAC7B,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;QACrC,eAAM,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC,CAAC;SACD,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;SACpE,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;QAC1B,gBAAQ,CAAC,kBAAkB,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEL,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,EAAE,CAAC,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,aAAa,OAAO,kBAAkB,CAAC,CAAC;AACtD,CAAC;AA5CD,sBA4CC","sourcesContent":["import chokidar from 'chokidar';\nimport { YargsArgs } from '../../types/yargs';\nimport { bundle } from '../build/bundle';\nimport {\n logError,\n getOutfilePath,\n validateDirPath,\n validateFilePath,\n validateOutfileName,\n} from '../../utils';\n\n/**\n * Watch a directory and its subdirectories for changes, and build when files\n * are added or changed.\n *\n * Ignores 'node_modules' and dotfiles.\n * Creates destination directory if it doesn't exist.\n *\n * @param argv - arguments as an object generated by yargs\n * @param argv.src - The source file path\n * @param argv.dist - The output directory path\n * @param argv.'outfileName' - The output file name\n */\nexport async function watch(argv: YargsArgs): Promise<void> {\n const { src, dist, outfileName } = argv;\n if (outfileName) {\n validateOutfileName(outfileName as string);\n }\n await validateFilePath(src);\n await validateDirPath(dist, true);\n const rootDir =\n src.indexOf('/') === -1 ? '.' : src.substring(0, src.lastIndexOf('/') + 1);\n const outfilePath = getOutfilePath(dist, outfileName as string);\n\n const watcher = chokidar.watch(rootDir, {\n ignoreInitial: true,\n ignored: [\n '**/node_modules/**',\n `**/${dist}/**`,\n `**/test/**`,\n `**/tests/**`,\n `**/*.test.js`,\n `**/*.test.ts`,\n /* istanbul ignore next */\n (str: string) => str !== '.' && str.startsWith('.'),\n ],\n });\n\n watcher\n .on('ready', () => {\n bundle(src, outfilePath, argv);\n })\n .on('add', (path: string) => {\n console.log(`File added: ${path}`);\n bundle(src, outfilePath, argv);\n })\n .on('change', (path: string) => {\n console.log(`File changed: ${path}`);\n bundle(src, outfilePath, argv);\n })\n .on('unlink', (path: string) => console.log(`File removed: ${path}`))\n .on('error', (err: Error) => {\n logError(`Watcher error: ${err.message}`, err);\n });\n\n watcher.add(`${rootDir}`);\n console.log(`Watching '${rootDir}' for changes...`);\n}\n"]}
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;;;;AACA,+BAA4B;AAC5B,kDAA8B;AAE9B,MAAM,CAAC,KAAK,GAAG;IACb,aAAa,EAAE,KAAK;IACpB,gBAAgB,EAAE,KAAK;IACvB,UAAU,EAAE,KAAK;CAClB,CAAC;AAEF,SAAG,CAAC,OAAO,CAAC,IAAI,EAAE,cAAQ,CAAC,CAAC","sourcesContent":["#!/usr/bin/env node\nimport { cli } from './cli';\nimport commands from './cmds';\n\nglobal.snaps = {\n verboseErrors: false,\n suppressWarnings: false,\n isWatching: false,\n};\n\ncli(process.argv, commands);\n"]}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;;;;AAEA,+BAA4B;AAC5B,kDAA8B;AAE9B,MAAM,CAAC,KAAK,GAAG;IACb,aAAa,EAAE,KAAK;IACpB,gBAAgB,EAAE,KAAK;IACvB,UAAU,EAAE,KAAK;CAClB,CAAC;AAEF,SAAG,CAAC,OAAO,CAAC,IAAI,EAAE,cAAQ,CAAC,CAAC","sourcesContent":["#!/usr/bin/env node\n\nimport { cli } from './cli';\nimport commands from './cmds';\n\nglobal.snaps = {\n verboseErrors: false,\n suppressWarnings: false,\n isWatching: false,\n};\n\ncli(process.argv, commands);\n"]}
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../tsconfig.test.json"
3
+ }
@@ -1,3 +1,4 @@
1
+ import type { Json } from '@metamask/snap-controllers';
1
2
  /**
2
3
  * Checks whether the given path string resolves to an existing directory, and
3
4
  * optionally creates the directory if it doesn't exist.
@@ -10,7 +11,14 @@ export declare function isDirectory(pathString: string, createDir: boolean): Pro
10
11
  /**
11
12
  * Checks whether the given path string resolves to an existing file.
12
13
  *
13
- * @param {string} pathString - The path string to check
14
- * @returns {boolean} - Whether the given path is an existing file
14
+ * @param pathString - The path string to check
15
+ * @returns Whether the given path is an existing file
15
16
  */
16
17
  export declare function isFile(pathString: string): Promise<boolean>;
18
+ /**
19
+ * Reads a `.json` file, parses its contents, and returns them.
20
+ *
21
+ * @param pathString - The path to the JSON file.
22
+ * @returns The parsed contents of the JSON file.
23
+ */
24
+ export declare function readJsonFile(pathString: string): Promise<Json>;
package/dist/utils/fs.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isFile = exports.isDirectory = void 0;
3
+ exports.readJsonFile = exports.isFile = exports.isDirectory = void 0;
4
4
  const fs_1 = require("fs");
5
5
  const misc_1 = require("./misc");
6
6
  /**
@@ -37,8 +37,8 @@ exports.isDirectory = isDirectory;
37
37
  /**
38
38
  * Checks whether the given path string resolves to an existing file.
39
39
  *
40
- * @param {string} pathString - The path string to check
41
- * @returns {boolean} - Whether the given path is an existing file
40
+ * @param pathString - The path string to check
41
+ * @returns Whether the given path is an existing file
42
42
  */
43
43
  async function isFile(pathString) {
44
44
  try {
@@ -50,4 +50,17 @@ async function isFile(pathString) {
50
50
  }
51
51
  }
52
52
  exports.isFile = isFile;
53
+ /**
54
+ * Reads a `.json` file, parses its contents, and returns them.
55
+ *
56
+ * @param pathString - The path to the JSON file.
57
+ * @returns The parsed contents of the JSON file.
58
+ */
59
+ async function readJsonFile(pathString) {
60
+ if (!pathString.endsWith('.json')) {
61
+ throw new Error('The specified file must be a ".json" file.');
62
+ }
63
+ return JSON.parse(await fs_1.promises.readFile(pathString, 'utf8'));
64
+ }
65
+ exports.readJsonFile = readJsonFile;
53
66
  //# sourceMappingURL=fs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":";;;AAAA,2BAAoC;AACpC,iCAAkC;AAElC;;;;;;;GAOG;AACI,KAAK,UAAU,WAAW,CAC/B,UAAkB,EAClB,SAAkB;IAElB,IAAI;QACF,MAAM,KAAK,GAAG,MAAM,aAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxC,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC;KAC5B;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE;YAC3B,IAAI,CAAC,SAAS,EAAE;gBACd,OAAO,KAAK,CAAC;aACd;YAED,IAAI;gBACF,MAAM,aAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBAC3B,OAAO,IAAI,CAAC;aACb;YAAC,OAAO,UAAU,EAAE;gBACnB,eAAQ,CAAC,cAAc,UAAU,yBAAyB,EAAE,UAAU,CAAC,CAAC;gBACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aACjB;SACF;QACD,OAAO,KAAK,CAAC;KACd;AACH,CAAC;AAvBD,kCAuBC;AAED;;;;;GAKG;AACI,KAAK,UAAU,MAAM,CAAC,UAAkB;IAC7C,IAAI;QACF,MAAM,KAAK,GAAG,MAAM,aAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxC,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;KACvB;IAAC,OAAO,KAAK,EAAE;QACd,OAAO,KAAK,CAAC;KACd;AACH,CAAC;AAPD,wBAOC","sourcesContent":["import { promises as fs } from 'fs';\nimport { logError } from './misc';\n\n/**\n * Checks whether the given path string resolves to an existing directory, and\n * optionally creates the directory if it doesn't exist.\n *\n * @param pathString - The path string to check\n * @param createDir - Whether to create the directory if it doesn't exist\n * @returns - Whether the given path is an existing directory\n */\nexport async function isDirectory(\n pathString: string,\n createDir: boolean,\n): Promise<boolean> {\n try {\n const stats = await fs.stat(pathString);\n return stats.isDirectory();\n } catch (error) {\n if (error.code === 'ENOENT') {\n if (!createDir) {\n return false;\n }\n\n try {\n await fs.mkdir(pathString);\n return true;\n } catch (mkdirError) {\n logError(`Directory '${pathString}' could not be created.`, mkdirError);\n process.exit(1);\n }\n }\n return false;\n }\n}\n\n/**\n * Checks whether the given path string resolves to an existing file.\n *\n * @param {string} pathString - The path string to check\n * @returns {boolean} - Whether the given path is an existing file\n */\nexport async function isFile(pathString: string): Promise<boolean> {\n try {\n const stats = await fs.stat(pathString);\n return stats.isFile();\n } catch (error) {\n return false;\n }\n}\n"]}
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":";;;AAAA,2BAAoC;AAEpC,iCAAkC;AAElC;;;;;;;GAOG;AACI,KAAK,UAAU,WAAW,CAC/B,UAAkB,EAClB,SAAkB;IAElB,IAAI;QACF,MAAM,KAAK,GAAG,MAAM,aAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxC,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC;KAC5B;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE;YAC3B,IAAI,CAAC,SAAS,EAAE;gBACd,OAAO,KAAK,CAAC;aACd;YAED,IAAI;gBACF,MAAM,aAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBAC3B,OAAO,IAAI,CAAC;aACb;YAAC,OAAO,UAAU,EAAE;gBACnB,eAAQ,CAAC,cAAc,UAAU,yBAAyB,EAAE,UAAU,CAAC,CAAC;gBACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aACjB;SACF;QACD,OAAO,KAAK,CAAC;KACd;AACH,CAAC;AAvBD,kCAuBC;AAED;;;;;GAKG;AACI,KAAK,UAAU,MAAM,CAAC,UAAkB;IAC7C,IAAI;QACF,MAAM,KAAK,GAAG,MAAM,aAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxC,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;KACvB;IAAC,OAAO,KAAK,EAAE;QACd,OAAO,KAAK,CAAC;KACd;AACH,CAAC;AAPD,wBAOC;AAED;;;;;GAKG;AACI,KAAK,UAAU,YAAY,CAAC,UAAkB;IACnD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;QACjC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;KAC/D;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,aAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AAC3D,CAAC;AAND,oCAMC","sourcesContent":["import { promises as fs } from 'fs';\nimport type { Json } from '@metamask/snap-controllers';\nimport { logError } from './misc';\n\n/**\n * Checks whether the given path string resolves to an existing directory, and\n * optionally creates the directory if it doesn't exist.\n *\n * @param pathString - The path string to check\n * @param createDir - Whether to create the directory if it doesn't exist\n * @returns - Whether the given path is an existing directory\n */\nexport async function isDirectory(\n pathString: string,\n createDir: boolean,\n): Promise<boolean> {\n try {\n const stats = await fs.stat(pathString);\n return stats.isDirectory();\n } catch (error) {\n if (error.code === 'ENOENT') {\n if (!createDir) {\n return false;\n }\n\n try {\n await fs.mkdir(pathString);\n return true;\n } catch (mkdirError) {\n logError(`Directory '${pathString}' could not be created.`, mkdirError);\n process.exit(1);\n }\n }\n return false;\n }\n}\n\n/**\n * Checks whether the given path string resolves to an existing file.\n *\n * @param pathString - The path string to check\n * @returns Whether the given path is an existing file\n */\nexport async function isFile(pathString: string): Promise<boolean> {\n try {\n const stats = await fs.stat(pathString);\n return stats.isFile();\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Reads a `.json` file, parses its contents, and returns them.\n *\n * @param pathString - The path to the JSON file.\n * @returns The parsed contents of the JSON file.\n */\nexport async function readJsonFile(pathString: string): Promise<Json> {\n if (!pathString.endsWith('.json')) {\n throw new Error('The specified file must be a \".json\" file.');\n }\n\n return JSON.parse(await fs.readFile(pathString, 'utf8'));\n}\n"]}
@@ -1,18 +1,19 @@
1
1
  import { Arguments } from 'yargs';
2
+ export declare const deepClone: <T>(input: T) => T;
2
3
  export declare const permRequestKeys: string[];
3
- export declare const CONFIG_PATHS: string[];
4
+ export declare const CONFIG_FILE = "snap.config.json";
4
5
  /**
5
6
  * Sets global variable snaps which tracks user settings:
6
7
  * watch mode activation, verbose errors messages, and whether to suppress warnings.
7
8
  *
8
- * @param {Argument} argv - arguments as an object generated by yargs
9
+ * @param argv - arguments as an object generated by yargs
9
10
  */
10
11
  export declare function setSnapGlobals(argv: Arguments): void;
11
12
  /**
12
13
  * Sanitizes inputs. Currently normalizes "./" paths to ".".
13
14
  * Yargs handles other path normalization as specified in builders.
14
15
  *
15
- * @param {Argument} argv - arguments as an object generated by yargs
16
+ * @param argv - arguments as an object generated by yargs
16
17
  */
17
18
  export declare function sanitizeInputs(argv: Arguments): void;
18
19
  /**