@metamask/snaps-cli 0.22.2 → 0.23.0

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.
@@ -3,290 +3,126 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.isTemplateTypescript = exports.correctDefaultArgs = exports.prepareWorkingDirectory = exports.buildSnapManifest = exports.asyncPackageInit = void 0;
6
+ exports.yarnInstall = exports.gitInit = exports.isInGitRepository = exports.isGitInstalled = exports.cloneTemplate = exports.prepareWorkingDirectory = exports.SNAP_LOCATION = exports.TEMPLATE_GIT_URL = void 0;
7
7
  const fs_1 = require("fs");
8
+ const child_process_1 = require("child_process");
8
9
  const path_1 = __importDefault(require("path"));
9
- const snap_utils_1 = require("@metamask/snap-utils");
10
- const init_package_json_1 = __importDefault(require("init-package-json"));
11
- const mkdirp_1 = __importDefault(require("mkdirp"));
12
- const slash_1 = __importDefault(require("slash"));
13
10
  const utils_1 = require("../../utils");
14
- const builders_1 = require("../../builders");
11
+ exports.TEMPLATE_GIT_URL = 'https://github.com/MetaMask/template-snap-monorepo.git';
12
+ exports.SNAP_LOCATION = 'packages/snap/';
15
13
  /**
16
- * This is a placeholder shasum that will be replaced at the end of the init command.
17
- */
18
- const PLACEHOLDER_SHASUM = '2QqUxo5joo4kKKr7yiCjdYsZOZcIFBnIBEdwU9Yx7+M=';
19
- const NPM_PUBLIC_REGISTRY_URL = 'https://registry.npmjs.org';
20
- /**
21
- * Initializes a `package.json` file for a Snap project. Will attempt to read
22
- * and parse the existing file if it already exists, otherwise will intialize
23
- * a brand new one.
24
- *
25
- * @param argv - Yargs arguments object.
26
- * @returns The contents of the `package.json` file.
27
- */
28
- async function asyncPackageInit(argv) {
29
- if ((0, fs_1.existsSync)(snap_utils_1.NpmSnapFileNames.PackageJson)) {
30
- console.log(`Init: Attempting to use existing '${snap_utils_1.NpmSnapFileNames.PackageJson}'...`);
31
- try {
32
- const packageJson = await (0, snap_utils_1.readJsonFile)(snap_utils_1.NpmSnapFileNames.PackageJson);
33
- (0, snap_utils_1.validateSnapJsonFile)(snap_utils_1.NpmSnapFileNames.PackageJson, packageJson);
34
- console.log(`Init: Successfully parsed '${snap_utils_1.NpmSnapFileNames.PackageJson}'!`);
35
- return packageJson;
36
- }
37
- catch (error) {
38
- (0, utils_1.logError)(`Init Error: Could not parse '${snap_utils_1.NpmSnapFileNames.PackageJson}'. Please verify that the file is correctly formatted and try again.`, error);
39
- throw error;
40
- }
41
- }
42
- // Exit if yarn.lock is found, or we'll be in trouble
43
- if ((0, fs_1.existsSync)('yarn.lock')) {
44
- (0, utils_1.logError)(`Init Error: Found a 'yarn.lock' file but no '${snap_utils_1.NpmSnapFileNames.PackageJson}'. Please run 'yarn init' and try again.`);
45
- throw new Error('Already existing yarn.lock file found');
46
- }
47
- // Run 'npm init'
48
- return new Promise((resolve, reject) => {
49
- (0, init_package_json_1.default)(process.cwd(), '', {
50
- 'init.main': argv.src,
51
- }, (err, data) => {
52
- if (err) {
53
- reject(err);
54
- }
55
- else {
56
- resolve(data);
57
- }
58
- });
59
- });
60
- }
61
- exports.asyncPackageInit = asyncPackageInit;
62
- const YES = 'yes';
63
- const YES_VALUES = new Set([YES, 'y']);
64
- /**
65
- * Checks if user input provided over a prompt is "yes", i.e., if the value is
66
- * truthy and in the {@link YES_VALUES} set.
67
- *
68
- * @param userInput - The user input to check.
69
- * @returns `true` if the user input is "yes", `false` otherwise.
70
- */
71
- function isYes(userInput) {
72
- return userInput && YES_VALUES.has(userInput.toLowerCase());
73
- }
74
- const DEFAULT_PERMISSION_KEY = 'snap_confirm';
75
- /**
76
- * Get the default permissions to write to the snap manifest.
14
+ * Checks if the destination folder exists and if it's empty. Otherwise create it.
77
15
  *
78
- * @returns An object containing the default permissions.
16
+ * @param directory - The desination folder.
79
17
  */
80
- const getDefaultPermissions = () => {
81
- return { [DEFAULT_PERMISSION_KEY]: {} };
82
- };
83
- /**
84
- * Interactively constructs a Snap manifest file by prompting the user.
85
- *
86
- * @param argv - The `yargs` `argv` object.
87
- * @param packageJson - The `package.json` object.
88
- * @returns A tuple of the resulting Snap manifest object and a new `argv`
89
- * object with properties to match the manifest.
90
- */
91
- async function buildSnapManifest(argv, packageJson) {
92
- const { outfileName } = argv;
93
- let { dist } = argv;
94
- let initialPermissions = getDefaultPermissions();
95
- let { description, name: proposedName } = packageJson;
96
- if (!description) {
97
- description = `The ${proposedName} Snap.`;
98
- }
18
+ async function prepareWorkingDirectory(directory) {
99
19
  try {
100
- const userInput = await (0, utils_1.prompt)({
101
- question: `Use default Snap manifest values?`,
102
- defaultValue: YES,
103
- shouldClose: false,
104
- });
105
- if (isYes(userInput)) {
106
- console.log('Using default values...');
20
+ const isCurrentDirectory = directory === process.cwd();
21
+ if (!isCurrentDirectory) {
107
22
  try {
108
- await (0, mkdirp_1.default)(dist);
23
+ await fs_1.promises.mkdir(directory, { recursive: true });
109
24
  }
110
25
  catch (err) {
111
- (0, utils_1.logError)(`Init Error: Could not write default 'dist' '${dist}'. Maybe check your local ${utils_1.CONFIG_FILE} file?`);
26
+ (0, utils_1.logError)('Init Error: Failed to create new directory.', err);
112
27
  throw err;
113
28
  }
114
- return endSnapManifest();
29
+ }
30
+ const existingFiles = await fs_1.promises.readdir(directory);
31
+ if (existingFiles.length > 0) {
32
+ throw new Error(`Directory not empty: ${directory}.`);
115
33
  }
116
34
  }
117
35
  catch (err) {
118
- (0, utils_1.logError)(`Init Error: ${err.message}`, err);
36
+ (0, utils_1.logError)('Init Error: Failed to prepare working directory.', err);
119
37
  throw err;
120
38
  }
121
- let invalidProposedName = true;
122
- while (invalidProposedName) {
123
- // eslint-disable-next-line require-atomic-updates
124
- proposedName = await (0, utils_1.prompt)({
125
- question: `Proposed Snap name:`,
126
- defaultValue: proposedName,
127
- });
128
- if (proposedName.length > 0 &&
129
- proposedName.length <= 214 &&
130
- snap_utils_1.PROPOSED_NAME_REGEX.test(proposedName)) {
131
- invalidProposedName = false;
132
- }
133
- else {
134
- (0, utils_1.logError)(`The proposed name must adhere to npm package naming conventions, except that capital letters are allowed. For details, see: https://docs.npmjs.com/cli/v6/configuring-npm/package-json#name`);
135
- }
136
- }
137
- let invalidDescription = true;
138
- while (invalidDescription) {
139
- // eslint-disable-next-line require-atomic-updates
140
- description = await (0, utils_1.prompt)({
141
- question: `Description:`,
142
- defaultValue: description,
39
+ }
40
+ exports.prepareWorkingDirectory = prepareWorkingDirectory;
41
+ /**
42
+ * Clones the template in a directory.
43
+ *
44
+ * @param directory - The directory to clone the template in.
45
+ */
46
+ async function cloneTemplate(directory) {
47
+ try {
48
+ (0, child_process_1.execSync)(`git clone --depth=1 ${exports.TEMPLATE_GIT_URL} ${directory}`, {
49
+ stdio: [2],
143
50
  });
144
- if (description.length === 0 || description.length <= 280) {
145
- invalidDescription = false;
146
- }
147
- else {
148
- (0, utils_1.logError)(`The description must be a non-empty string less than or equal to 280 characters.`);
149
- }
150
51
  }
151
- let invalidDist = true;
152
- while (invalidDist) {
153
- // eslint-disable-next-line require-atomic-updates
154
- dist = await (0, utils_1.prompt)({ question: `Output directory:`, defaultValue: dist });
155
- try {
156
- dist = (0, utils_1.trimPathString)(dist);
157
- await (0, mkdirp_1.default)(dist);
158
- invalidDist = false;
159
- }
160
- catch (distError) {
161
- (0, utils_1.logError)(`Unable to create directory '${dist}'. Ensure that the path is valid and try again.`, distError);
162
- }
52
+ catch (err) {
53
+ (0, utils_1.logError)('Init Error: Failed to clone the template.', err);
54
+ throw err;
163
55
  }
164
- let invalidPermissions = true;
165
- while (invalidPermissions) {
166
- const inputPermissions = await (0, utils_1.prompt)({
167
- // We add the parenthetical default value ourselves
168
- question: `Initial permissions: [perm1 perm2 ...] ([snap_confirm])`,
169
- });
170
- if (!inputPermissions ||
171
- inputPermissions.trim() === DEFAULT_PERMISSION_KEY) {
172
- break;
173
- }
174
- try {
175
- initialPermissions = inputPermissions
176
- .split(' ')
177
- .reduce((allPermissions, permission) => {
178
- if (typeof permission === 'string' &&
179
- permission.match(/^[\w\d_:]+$/iu)) {
180
- allPermissions[permission] = {};
181
- }
182
- else {
183
- throw new Error(`Invalid permission: ${permission}`);
184
- }
185
- return allPermissions;
186
- }, {});
187
- invalidPermissions = false;
188
- }
189
- catch (err) {
190
- (0, utils_1.logError)(`Invalid permissions '${inputPermissions}'.\nThe permissions must be specified as a space-separated list of strings with only characters, digits, underscores ('_'), and colons (':').`, err);
191
- }
56
+ }
57
+ exports.cloneTemplate = cloneTemplate;
58
+ /**
59
+ * Check if git is installed.
60
+ *
61
+ * @returns True if git is installed, or false otherwise.
62
+ */
63
+ function isGitInstalled() {
64
+ try {
65
+ (0, child_process_1.execSync)('git --version', { stdio: 'ignore' });
66
+ return true;
192
67
  }
193
- return endSnapManifest();
194
- /**
195
- * Get the final snap manifest object and return it, along with the dist and
196
- * file names.
197
- *
198
- * @returns A tuple of the resulting snap manifest object and an object
199
- * containing the dist and file names.
200
- */
201
- function endSnapManifest() {
202
- const manifest = {
203
- version: packageJson.version,
204
- description,
205
- proposedName,
206
- repository: packageJson.repository
207
- ? (0, snap_utils_1.deepClone)(packageJson.repository)
208
- : null,
209
- source: {
210
- shasum: PLACEHOLDER_SHASUM,
211
- location: {
212
- npm: {
213
- filePath: (0, slash_1.default)(path_1.default.join(dist, outfileName)),
214
- packageName: packageJson.name,
215
- registry: NPM_PUBLIC_REGISTRY_URL,
216
- iconPath: 'images/icon.svg',
217
- },
218
- },
219
- },
220
- initialPermissions,
221
- manifestVersion: '0.1',
222
- };
223
- try {
224
- (0, snap_utils_1.validateSnapJsonFile)(snap_utils_1.NpmSnapFileNames.Manifest, manifest);
225
- }
226
- catch (error) {
227
- /* istanbul ignore next */
228
- throw new Error(`Internal Error: Validation of constructed manifest failed. This is a bug, please report it. Reason:\n${error.message}`);
229
- }
230
- return [
231
- manifest,
232
- { dist, outfileName, src: packageJson.main || 'src/index.js' },
233
- ];
68
+ catch (e) {
69
+ return false;
234
70
  }
235
71
  }
236
- exports.buildSnapManifest = buildSnapManifest;
237
- const INIT_FILE_NAMES = new Set([
238
- 'src',
239
- 'index.html',
240
- utils_1.CONFIG_FILE,
241
- 'dist',
242
- snap_utils_1.NpmSnapFileNames.Manifest,
243
- ]);
72
+ exports.isGitInstalled = isGitInstalled;
244
73
  /**
245
- * Checks whether any files in the current working directory will be overwritten
246
- * by the initialization process, and asks the user whether to continue if so.
74
+ * Check if the actual working dir is a git repository.
75
+ *
76
+ * @param directory - The directory to check.
77
+ * @returns True if it's a git repository otherwise false.
247
78
  */
248
- async function prepareWorkingDirectory() {
249
- const existingFiles = (await fs_1.promises.readdir(process.cwd())).filter((item) => INIT_FILE_NAMES.has(item.toString()));
250
- if (existingFiles.length > 0) {
251
- (0, utils_1.logWarning)(`\nInit Warning: Existing files and/or directories may be overwritten:\n${existingFiles.reduce((message, currentFile) => {
252
- return `${message}\t${currentFile}\n`;
253
- }, '')}`);
254
- const continueInput = await (0, utils_1.prompt)({
255
- question: `Continue?`,
256
- defaultValue: YES,
79
+ function isInGitRepository(directory) {
80
+ try {
81
+ (0, child_process_1.execSync)('git rev-parse --is-inside-work-tree', {
82
+ stdio: 'ignore',
83
+ cwd: path_1.default.resolve(__dirname, directory),
257
84
  });
258
- const shouldContinue = continueInput && isYes(continueInput);
259
- if (!shouldContinue) {
260
- console.log(`Init: Exiting...`);
261
- throw new Error('User refused to continue');
262
- }
85
+ return true;
86
+ }
87
+ catch (err) {
88
+ return false;
263
89
  }
264
90
  }
265
- exports.prepareWorkingDirectory = prepareWorkingDirectory;
91
+ exports.isInGitRepository = isInGitRepository;
266
92
  /**
267
- * In case when TypeScript version is used, default source file
268
- * will be updated if previous was not correct.
93
+ * Init a git repository.
269
94
  *
270
- * @param yargsArgv - The Yargs arguments object.
271
- * @returns Modified Yargs arguments object.
95
+ * @param directory - The directory to init.
272
96
  */
273
- function correctDefaultArgs(yargsArgv) {
274
- if (yargsArgv.template === builders_1.TemplateType.TypeScript &&
275
- yargsArgv.src === 'src/index.js') {
276
- yargsArgv.src = 'src/index.ts';
277
- yargsArgv.s = 'src/index.ts';
97
+ async function gitInit(directory) {
98
+ try {
99
+ (0, child_process_1.execSync)('git init', {
100
+ stdio: 'ignore',
101
+ cwd: path_1.default.resolve(__dirname, directory),
102
+ });
103
+ }
104
+ catch (err) {
105
+ (0, utils_1.logError)('Init Error: Failed to init a new git repository.', err);
106
+ throw err;
278
107
  }
279
- return yargsArgv;
280
108
  }
281
- exports.correctDefaultArgs = correctDefaultArgs;
109
+ exports.gitInit = gitInit;
282
110
  /**
283
- * Check if template argument is TemplateType.TypeScript.
111
+ * Install dependencies in a yarn project.
284
112
  *
285
- * @param templateType - TemplateType value of the template argument passed from CLI.
286
- * @returns True or false.
113
+ * @param directory - The directory containing the project.
287
114
  */
288
- function isTemplateTypescript(templateType) {
289
- return templateType === builders_1.TemplateType.TypeScript;
115
+ async function yarnInstall(directory) {
116
+ try {
117
+ (0, child_process_1.execSync)('yarn install', {
118
+ stdio: [0, 1, 2],
119
+ cwd: path_1.default.resolve(__dirname, directory),
120
+ });
121
+ }
122
+ catch (err) {
123
+ (0, utils_1.logError)('Init Error: Failed to install dependencies.', err);
124
+ throw err;
125
+ }
290
126
  }
291
- exports.isTemplateTypescript = isTemplateTypescript;
127
+ exports.yarnInstall = yarnInstall;
292
128
  //# sourceMappingURL=initUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"initUtils.js","sourceRoot":"","sources":["../../../src/cmds/init/initUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, promises as fs } from 'fs';\nimport pathUtils from 'path';\nimport {\n PROPOSED_NAME_REGEX,\n NpmSnapFileNames,\n SnapManifest,\n NpmSnapPackageJson,\n validateSnapJsonFile,\n readJsonFile,\n deepClone,\n} from '@metamask/snap-utils';\nimport initPackageJson from 'init-package-json';\nimport mkdirp from 'mkdirp';\nimport slash from 'slash';\nimport { Arguments } from 'yargs';\nimport { YargsArgs } from '../../types/yargs';\nimport {\n CONFIG_FILE,\n logError,\n logWarning,\n prompt,\n trimPathString,\n} from '../../utils';\nimport { TemplateType } from '../../builders';\n\n/**\n * This is a placeholder shasum that will be replaced at the end of the init command.\n */\nconst PLACEHOLDER_SHASUM = '2QqUxo5joo4kKKr7yiCjdYsZOZcIFBnIBEdwU9Yx7+M=';\n\nconst NPM_PUBLIC_REGISTRY_URL = 'https://registry.npmjs.org';\n\n/**\n * Initializes a `package.json` file for a Snap project. Will attempt to read\n * and parse the existing file if it already exists, otherwise will intialize\n * a brand new one.\n *\n * @param argv - Yargs arguments object.\n * @returns The contents of the `package.json` file.\n */\nexport async function asyncPackageInit(\n argv: YargsArgs,\n): Promise<Readonly<NpmSnapPackageJson>> {\n if (existsSync(NpmSnapFileNames.PackageJson)) {\n console.log(\n `Init: Attempting to use existing '${NpmSnapFileNames.PackageJson}'...`,\n );\n\n try {\n const packageJson = await readJsonFile(NpmSnapFileNames.PackageJson);\n validateSnapJsonFile(NpmSnapFileNames.PackageJson, packageJson);\n\n console.log(\n `Init: Successfully parsed '${NpmSnapFileNames.PackageJson}'!`,\n );\n return packageJson as NpmSnapPackageJson;\n } catch (error) {\n logError(\n `Init Error: Could not parse '${NpmSnapFileNames.PackageJson}'. Please verify that the file is correctly formatted and try again.`,\n error,\n );\n throw error;\n }\n }\n\n // Exit if yarn.lock is found, or we'll be in trouble\n if (existsSync('yarn.lock')) {\n logError(\n `Init Error: Found a 'yarn.lock' file but no '${NpmSnapFileNames.PackageJson}'. Please run 'yarn init' and try again.`,\n );\n throw new Error('Already existing yarn.lock file found');\n }\n\n // Run 'npm init'\n return new Promise((resolve, reject) => {\n initPackageJson(\n process.cwd(),\n '',\n {\n 'init.main': argv.src,\n },\n (err, data) => {\n if (err) {\n reject(err);\n } else {\n resolve(data);\n }\n },\n );\n });\n}\n\nconst YES = 'yes';\nconst YES_VALUES = new Set([YES, 'y']);\n\n/**\n * Checks if user input provided over a prompt is \"yes\", i.e., if the value is\n * truthy and in the {@link YES_VALUES} set.\n *\n * @param userInput - The user input to check.\n * @returns `true` if the user input is \"yes\", `false` otherwise.\n */\nfunction isYes(userInput: string | undefined) {\n return userInput && YES_VALUES.has(userInput.toLowerCase());\n}\n\nconst DEFAULT_PERMISSION_KEY = 'snap_confirm';\n\n/**\n * Get the default permissions to write to the snap manifest.\n *\n * @returns An object containing the default permissions.\n */\nconst getDefaultPermissions = () => {\n return { [DEFAULT_PERMISSION_KEY]: {} };\n};\n\n/**\n * Interactively constructs a Snap manifest file by prompting the user.\n *\n * @param argv - The `yargs` `argv` object.\n * @param packageJson - The `package.json` object.\n * @returns A tuple of the resulting Snap manifest object and a new `argv`\n * object with properties to match the manifest.\n */\nexport async function buildSnapManifest(\n argv: YargsArgs,\n packageJson: NpmSnapPackageJson,\n): Promise<[SnapManifest, { dist: string; outfileName: string; src: string }]> {\n const { outfileName } = argv;\n let { dist } = argv;\n let initialPermissions: Record<string, unknown> = getDefaultPermissions();\n let { description, name: proposedName } = packageJson;\n\n if (!description) {\n description = `The ${proposedName} Snap.`;\n }\n\n try {\n const userInput = await prompt({\n question: `Use default Snap manifest values?`,\n defaultValue: YES,\n shouldClose: false,\n });\n\n if (isYes(userInput)) {\n console.log('Using default values...');\n try {\n await mkdirp(dist);\n } catch (err) {\n logError(\n `Init Error: Could not write default 'dist' '${dist}'. Maybe check your local ${CONFIG_FILE} file?`,\n );\n throw err;\n }\n return endSnapManifest();\n }\n } catch (err) {\n logError(`Init Error: ${err.message}`, err);\n throw err;\n }\n\n let invalidProposedName = true;\n while (invalidProposedName) {\n // eslint-disable-next-line require-atomic-updates\n proposedName = await prompt({\n question: `Proposed Snap name:`,\n defaultValue: proposedName,\n });\n\n if (\n proposedName.length > 0 &&\n proposedName.length <= 214 &&\n PROPOSED_NAME_REGEX.test(proposedName)\n ) {\n invalidProposedName = false;\n } else {\n logError(\n `The proposed name must adhere to npm package naming conventions, except that capital letters are allowed. For details, see: https://docs.npmjs.com/cli/v6/configuring-npm/package-json#name`,\n );\n }\n }\n\n let invalidDescription = true;\n while (invalidDescription) {\n // eslint-disable-next-line require-atomic-updates\n description = await prompt({\n question: `Description:`,\n defaultValue: description,\n });\n\n if (description.length === 0 || description.length <= 280) {\n invalidDescription = false;\n } else {\n logError(\n `The description must be a non-empty string less than or equal to 280 characters.`,\n );\n }\n }\n\n let invalidDist = true;\n while (invalidDist) {\n // eslint-disable-next-line require-atomic-updates\n dist = await prompt({ question: `Output directory:`, defaultValue: dist });\n try {\n dist = trimPathString(dist);\n await mkdirp(dist);\n invalidDist = false;\n } catch (distError) {\n logError(\n `Unable to create directory '${dist}'. Ensure that the path is valid and try again.`,\n distError,\n );\n }\n }\n\n let invalidPermissions = true;\n while (invalidPermissions) {\n const inputPermissions = await prompt({\n // We add the parenthetical default value ourselves\n question: `Initial permissions: [perm1 perm2 ...] ([snap_confirm])`,\n });\n\n if (\n !inputPermissions ||\n inputPermissions.trim() === DEFAULT_PERMISSION_KEY\n ) {\n break;\n }\n\n try {\n initialPermissions = inputPermissions\n .split(' ')\n .reduce((allPermissions, permission) => {\n if (\n typeof permission === 'string' &&\n permission.match(/^[\\w\\d_:]+$/iu)\n ) {\n allPermissions[permission] = {};\n } else {\n throw new Error(`Invalid permission: ${permission}`);\n }\n return allPermissions;\n }, {} as Record<string, unknown>);\n\n invalidPermissions = false;\n } catch (err) {\n logError(\n `Invalid permissions '${inputPermissions}'.\\nThe permissions must be specified as a space-separated list of strings with only characters, digits, underscores ('_'), and colons (':').`,\n err,\n );\n }\n }\n\n return endSnapManifest();\n\n /**\n * Get the final snap manifest object and return it, along with the dist and\n * file names.\n *\n * @returns A tuple of the resulting snap manifest object and an object\n * containing the dist and file names.\n */\n function endSnapManifest(): [\n SnapManifest,\n {\n dist: string;\n outfileName: string;\n src: string;\n },\n ] {\n const manifest = {\n version: packageJson.version,\n description,\n proposedName,\n repository: packageJson.repository\n ? deepClone(packageJson.repository)\n : null,\n source: {\n shasum: PLACEHOLDER_SHASUM,\n location: {\n npm: {\n filePath: slash(pathUtils.join(dist, outfileName)),\n packageName: packageJson.name,\n registry: NPM_PUBLIC_REGISTRY_URL,\n iconPath: 'images/icon.svg',\n } as const,\n },\n },\n initialPermissions,\n manifestVersion: '0.1' as const,\n };\n\n try {\n validateSnapJsonFile(NpmSnapFileNames.Manifest, manifest);\n } catch (error) {\n /* istanbul ignore next */\n throw new Error(\n `Internal Error: Validation of constructed manifest failed. This is a bug, please report it. Reason:\\n${error.message}`,\n );\n }\n\n return [\n manifest,\n { dist, outfileName, src: packageJson.main || 'src/index.js' },\n ];\n }\n}\n\nconst INIT_FILE_NAMES = new Set([\n 'src',\n 'index.html',\n CONFIG_FILE,\n 'dist',\n NpmSnapFileNames.Manifest,\n]);\n\n/**\n * Checks whether any files in the current working directory will be overwritten\n * by the initialization process, and asks the user whether to continue if so.\n */\nexport async function prepareWorkingDirectory(): Promise<void> {\n const existingFiles = (await fs.readdir(process.cwd())).filter((item) =>\n INIT_FILE_NAMES.has(item.toString()),\n );\n\n if (existingFiles.length > 0) {\n logWarning(\n `\\nInit Warning: Existing files and/or directories may be overwritten:\\n${existingFiles.reduce(\n (message, currentFile) => {\n return `${message}\\t${currentFile}\\n`;\n },\n '',\n )}`,\n );\n\n const continueInput = await prompt({\n question: `Continue?`,\n defaultValue: YES,\n });\n const shouldContinue = continueInput && isYes(continueInput);\n\n if (!shouldContinue) {\n console.log(`Init: Exiting...`);\n throw new Error('User refused to continue');\n }\n }\n}\n\n/**\n * In case when TypeScript version is used, default source file\n * will be updated if previous was not correct.\n *\n * @param yargsArgv - The Yargs arguments object.\n * @returns Modified Yargs arguments object.\n */\nexport function correctDefaultArgs(yargsArgv: Arguments): Arguments {\n if (\n yargsArgv.template === TemplateType.TypeScript &&\n yargsArgv.src === 'src/index.js'\n ) {\n yargsArgv.src = 'src/index.ts';\n yargsArgv.s = 'src/index.ts';\n }\n\n return yargsArgv;\n}\n\n/**\n * Check if template argument is TemplateType.TypeScript.\n *\n * @param templateType - TemplateType value of the template argument passed from CLI.\n * @returns True or false.\n */\nexport function isTemplateTypescript(templateType: TemplateType): boolean {\n return templateType === TemplateType.TypeScript;\n}\n"]}
1
+ {"version":3,"file":"initUtils.js","sourceRoot":"","sources":["../../../src/cmds/init/initUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'fs';\nimport { execSync } from 'child_process';\nimport pathUtils from 'path';\nimport { logError } from '../../utils';\n\nexport const TEMPLATE_GIT_URL =\n 'https://github.com/MetaMask/template-snap-monorepo.git';\n\nexport const SNAP_LOCATION = 'packages/snap/';\n\n/**\n * Checks if the destination folder exists and if it's empty. Otherwise create it.\n *\n * @param directory - The desination folder.\n */\nexport async function prepareWorkingDirectory(\n directory: string,\n): Promise<void> {\n try {\n const isCurrentDirectory = directory === process.cwd();\n\n if (!isCurrentDirectory) {\n try {\n await fs.mkdir(directory, { recursive: true });\n } catch (err) {\n logError('Init Error: Failed to create new directory.', err);\n throw err;\n }\n }\n\n const existingFiles = await fs.readdir(directory);\n\n if (existingFiles.length > 0) {\n throw new Error(`Directory not empty: ${directory}.`);\n }\n } catch (err) {\n logError('Init Error: Failed to prepare working directory.', err);\n throw err;\n }\n}\n\n/**\n * Clones the template in a directory.\n *\n * @param directory - The directory to clone the template in.\n */\nexport async function cloneTemplate(directory: string) {\n try {\n execSync(`git clone --depth=1 ${TEMPLATE_GIT_URL} ${directory}`, {\n stdio: [2],\n });\n } catch (err) {\n logError('Init Error: Failed to clone the template.', err);\n throw err;\n }\n}\n\n/**\n * Check if git is installed.\n *\n * @returns True if git is installed, or false otherwise.\n */\nexport function isGitInstalled() {\n try {\n execSync('git --version', { stdio: 'ignore' });\n return true;\n } catch (e) {\n return false;\n }\n}\n\n/**\n * Check if the actual working dir is a git repository.\n *\n * @param directory - The directory to check.\n * @returns True if it's a git repository otherwise false.\n */\nexport function isInGitRepository(directory: string) {\n try {\n execSync('git rev-parse --is-inside-work-tree', {\n stdio: 'ignore',\n cwd: pathUtils.resolve(__dirname, directory),\n });\n return true;\n } catch (err) {\n return false;\n }\n}\n\n/**\n * Init a git repository.\n *\n * @param directory - The directory to init.\n */\nexport async function gitInit(directory: string) {\n try {\n execSync('git init', {\n stdio: 'ignore',\n cwd: pathUtils.resolve(__dirname, directory),\n });\n } catch (err) {\n logError('Init Error: Failed to init a new git repository.', err);\n throw err;\n }\n}\n\n/**\n * Install dependencies in a yarn project.\n *\n * @param directory - The directory containing the project.\n */\nexport async function yarnInstall(directory: string) {\n try {\n execSync('yarn install', {\n stdio: [0, 1, 2],\n cwd: pathUtils.resolve(__dirname, directory),\n });\n } catch (err) {\n logError('Init Error: Failed to install dependencies.', err);\n throw err;\n }\n}\n"]}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Clears out all the files in the in-memory file system, and writes the default
3
+ * folders to mimic the on-disk current working directory, including sub-folders.
4
+ */
5
+ export declare function resetFileSystem(): Promise<void>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resetFileSystem = void 0;
4
+ const fs_1 = require("fs");
5
+ jest.mock('fs');
6
+ /**
7
+ * Clears out all the files in the in-memory file system, and writes the default
8
+ * folders to mimic the on-disk current working directory, including sub-folders.
9
+ */
10
+ async function resetFileSystem() {
11
+ await fs_1.promises.rm(process.cwd(), { recursive: true, force: true });
12
+ // Using relative path with memfs won't work since process.cwd() specifies the cwd of the on-disk file system
13
+ // This recursively creates the current working directory in the memfs volume.
14
+ // Ref. https://github.com/streamich/memfs/blob/master/docs/relative-paths.md
15
+ await fs_1.promises.mkdir(process.cwd(), { recursive: true });
16
+ }
17
+ exports.resetFileSystem = resetFileSystem;
18
+ //# sourceMappingURL=fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/test-utils/fs.ts"],"names":[],"mappings":";;;AAAA,2BAAoC;AAEpC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEhB;;;GAGG;AACI,KAAK,UAAU,eAAe;IACnC,MAAM,aAAE,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAE7D,6GAA6G;IAC7G,8EAA8E;IAC9E,6EAA6E;IAC7E,MAAM,aAAE,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACrD,CAAC;AAPD,0CAOC","sourcesContent":["import { promises as fs } from 'fs';\n\njest.mock('fs');\n\n/**\n * Clears out all the files in the in-memory file system, and writes the default\n * folders to mimic the on-disk current working directory, including sub-folders.\n */\nexport async function resetFileSystem() {\n await fs.rm(process.cwd(), { recursive: true, force: true });\n\n // Using relative path with memfs won't work since process.cwd() specifies the cwd of the on-disk file system\n // This recursively creates the current working directory in the memfs volume.\n // Ref. https://github.com/streamich/memfs/blob/master/docs/relative-paths.md\n await fs.mkdir(process.cwd(), { recursive: true });\n}\n"]}
@@ -0,0 +1 @@
1
+ export * from './fs';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./fs"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/test-utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uCAAqB","sourcesContent":["export * from './fs';\n"]}
@@ -1,3 +1,2 @@
1
1
  export * from './misc';
2
- export * from './readline';
3
2
  export * from './snap-config';
@@ -15,6 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./misc"), exports);
18
- __exportStar(require("./readline"), exports);
19
18
  __exportStar(require("./snap-config"), exports);
20
19
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yCAAuB;AACvB,6CAA2B;AAC3B,gDAA8B","sourcesContent":["export * from './misc';\nexport * from './readline';\nexport * from './snap-config';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yCAAuB;AACvB,gDAA8B","sourcesContent":["export * from './misc';\nexport * from './snap-config';\n"]}
@@ -2,11 +2,28 @@
2
2
  import type browserify from 'browserify';
3
3
  import { Arguments } from 'yargs';
4
4
  import yargs from 'yargs/yargs';
5
- /** @see {isSnapConfig} ts-auto-guard:type-guard */
6
- export declare type SnapConfig = {
7
- cliOptions?: Record<string, unknown>;
8
- bundlerCustomizer?: (bundler: browserify.BrowserifyObject) => void;
5
+ import { Infer } from 'superstruct';
6
+ export declare type BundleCustomizer = (bundler: browserify.BrowserifyObject) => void;
7
+ export declare const SnapConfigStruct: import("superstruct").Struct<{
8
+ cliOptions?: Record<string, unknown> | undefined;
9
+ bundlerCustomizer?: Function | undefined;
10
+ }, {
11
+ cliOptions: import("superstruct").Struct<Record<string, unknown> | undefined, null>;
12
+ bundlerCustomizer: import("superstruct").Struct<Function | undefined, null>;
13
+ }>;
14
+ export declare type SnapConfig = Omit<Infer<typeof SnapConfigStruct>, 'bundlerCustomizer'> & {
15
+ bundlerCustomizer?: BundleCustomizer;
9
16
  };
17
+ /**
18
+ * Check if the given value is a {@link SnapConfig} object. Note that this
19
+ * function does not check the validity of the `bundleCustomizer` property, as
20
+ * it is not possible to check the validity of a function in JavaScript.
21
+ *
22
+ * @param value - The value to check.
23
+ * @returns `true` if the value is a valid {@link SnapConfig} object, `false`
24
+ * otherwise.
25
+ */
26
+ export declare function isSnapConfig(value: unknown): value is SnapConfig;
10
27
  /**
11
28
  * Attempt to load the snap config file (`snap.config.js`). By default will use
12
29
  * the cached config, if it was loaded before, and `cached` is `true`. If the
@@ -3,13 +3,30 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.applyConfig = exports.loadConfig = void 0;
6
+ exports.applyConfig = exports.loadConfig = exports.isSnapConfig = exports.SnapConfigStruct = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const utils_1 = require("@metamask/utils");
9
9
  const yargs_parser_1 = __importDefault(require("yargs-parser"));
10
+ const superstruct_1 = require("superstruct");
10
11
  const builders_1 = __importDefault(require("../builders"));
11
12
  const misc_1 = require("./misc");
12
- const snap_config___GENERATED__1 = require("./snap-config.__GENERATED__");
13
+ exports.SnapConfigStruct = (0, superstruct_1.object)({
14
+ cliOptions: (0, superstruct_1.optional)((0, superstruct_1.object)()),
15
+ bundlerCustomizer: (0, superstruct_1.optional)((0, superstruct_1.func)()),
16
+ });
17
+ /**
18
+ * Check if the given value is a {@link SnapConfig} object. Note that this
19
+ * function does not check the validity of the `bundleCustomizer` property, as
20
+ * it is not possible to check the validity of a function in JavaScript.
21
+ *
22
+ * @param value - The value to check.
23
+ * @returns `true` if the value is a valid {@link SnapConfig} object, `false`
24
+ * otherwise.
25
+ */
26
+ function isSnapConfig(value) {
27
+ return (0, superstruct_1.is)(value, exports.SnapConfigStruct);
28
+ }
29
+ exports.isSnapConfig = isSnapConfig;
13
30
  let snapConfigCache;
14
31
  /**
15
32
  * Attempt to load the snap config file (`snap.config.js`). By default will use
@@ -37,7 +54,7 @@ function loadConfig(cached = true) {
37
54
  (0, misc_1.logError)(`Error during parsing of ${misc_1.CONFIG_FILE}`, err);
38
55
  return process.exit(1);
39
56
  }
40
- if (!(0, snap_config___GENERATED__1.isSnapConfig)(config)) {
57
+ if (!isSnapConfig(config)) {
41
58
  (0, misc_1.logError)(`Can't validate ${misc_1.CONFIG_FILE}. Ensure it's a proper javascript file and abides with the structure of a snap configuration file`);
42
59
  return process.exit(1);
43
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"snap-config.js","sourceRoot":"","sources":["../../src/utils/snap-config.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AACxB,2CAA8C;AAG9C,gEAAsC;AAEtC,2DAAmC;AACnC,iCAA+C;AAC/C,0EAA2D;AAQ3D,IAAI,eAAuC,CAAC;AAE5C;;;;;;;;GAQG;AACH,SAAgB,UAAU,CAAC,MAAM,GAAG,IAAI;IACtC,IAAI,eAAe,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,EAAE;QACpD,OAAO,eAAe,CAAC;KACxB;IAED,IAAI,MAAW,CAAC;IAChB,IAAI;QACF,iHAAiH;QACjH,MAAM,GAAG,OAAO,CAAC,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,kBAAW,CAAC,CAAC,CAAC;KAC5D;IAAC,OAAO,GAAQ,EAAE;QACjB,IAAI,GAAG,CAAC,IAAI,KAAK,kBAAkB,EAAE;YACnC,eAAe,GAAG,EAAE,CAAC;YACrB,OAAO,eAAe,CAAC;SACxB;QACD,IAAA,eAAQ,EAAC,2BAA2B,kBAAW,EAAE,EAAE,GAAG,CAAC,CAAC;QACxD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACxB;IAED,IAAI,CAAC,IAAA,uCAAY,EAAC,MAAM,CAAC,EAAE;QACzB,IAAA,eAAQ,EACN,kBAAkB,kBAAW,mGAAmG,CACjI,CAAC;QACF,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACxB;IACD,eAAe,GAAG,MAAM,CAAC;IACzB,OAAO,MAAM,CAAC;AAChB,CAAC;AA1BD,gCA0BC;AAED,8EAA8E;AAC9E,6BAA6B;AAC7B,EAAE;AACF,wEAAwE;AACxE,4DAA4D;AAE5D;;;;;;;;;;;GAWG;AACH,SAAgB,WAAW,CACzB,UAAsB,EACtB,WAAqB,EACrB,SAAoB,EACpB,aAA2B;IAE3B,uEAAuE;IACvE,wEAAwE;IACxE,6EAA6E;IAC7E,+BAA+B;IAC/B,EAAE;IACF,8EAA8E;IAC9E,2EAA2E;IAC3E,oBAAoB;IACpB,EAAE;IACF,6EAA6E;IAC7E,qBAAqB;IACrB,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GACpC,aACD,CAAC,UAAU,EAGX,CAAC;IAEF,MAAM,iBAAiB,GAAG,IAAA,sBAAU,EAAC,WAAW,EAAE;QAChD,KAAK,EAAE,OAAO;KACf,CAA4B,CAAC;IAC9B,OAAO,iBAAiB,CAAC,CAAC,CAAC,CAAC,mCAAmC;IAE/D,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAErD,MAAM,YAAY,GAAG,CAAC,GAAW,EAAW,EAAE;QAC5C,OAAO,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAA,mBAAW,EAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;IACzE,CAAC,CAAC;IAEF,MAAM,GAAG,GAA4B,UAAU,CAAC,UAAU,IAAI,EAAE,CAAC;IACjE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QAClC,IAAI,IAAA,mBAAW,EAAC,kBAAQ,EAAE,GAAG,CAAC,EAAE;YAC9B,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE;gBACrB,SAAS,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;aAC3B;SACF;aAAM;YACL,IAAA,eAAQ,EACN,4DAA4D,GAAG,qBAAqB,kBAAW,uCAAuC,CACvI,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACjB;KACF;AACH,CAAC;AAhDD,kCAgDC","sourcesContent":["import path from 'path';\nimport { hasProperty } from '@metamask/utils';\nimport type browserify from 'browserify';\nimport { Arguments } from 'yargs';\nimport yargsParse from 'yargs-parser';\nimport yargs from 'yargs/yargs';\nimport builders from '../builders';\nimport { CONFIG_FILE, logError } from './misc';\nimport { isSnapConfig } from './snap-config.__GENERATED__';\n\n/** @see {isSnapConfig} ts-auto-guard:type-guard */\nexport type SnapConfig = {\n cliOptions?: Record<string, unknown>;\n bundlerCustomizer?: (bundler: browserify.BrowserifyObject) => void;\n};\n\nlet snapConfigCache: SnapConfig | undefined;\n\n/**\n * Attempt to load the snap config file (`snap.config.js`). By default will use\n * the cached config, if it was loaded before, and `cached` is `true`. If the\n * config file is not found, or the config is invalid, this function will kill\n * the process.\n *\n * @param cached - Whether to use the cached config. Defaults to `true`.\n * @returns The snap config.\n */\nexport function loadConfig(cached = true): SnapConfig {\n if (snapConfigCache !== undefined && cached === true) {\n return snapConfigCache;\n }\n\n let config: any;\n try {\n // eslint-disable-next-line node/global-require, import/no-dynamic-require, @typescript-eslint/no-require-imports\n config = require(path.resolve(process.cwd(), CONFIG_FILE));\n } catch (err: any) {\n if (err.code === 'MODULE_NOT_FOUND') {\n snapConfigCache = {};\n return snapConfigCache;\n }\n logError(`Error during parsing of ${CONFIG_FILE}`, err);\n return process.exit(1);\n }\n\n if (!isSnapConfig(config)) {\n logError(\n `Can't validate ${CONFIG_FILE}. Ensure it's a proper javascript file and abides with the structure of a snap configuration file`,\n );\n return process.exit(1);\n }\n snapConfigCache = config;\n return config;\n}\n\n// Note that the below function is necessary because yargs' .config() function\n// leaves much to be desired.\n//\n// In particular, it will set all properties included in the config file\n// regardless of the command, which fails during validation.\n\n/**\n * Attempts to read configuration options for package.json and the config file,\n * and apply them to argv if they weren't already set.\n *\n * Arguments are only set per the snap-cli config file if they were not specified\n * on the command line.\n *\n * @param snapConfig - The snap config.\n * @param processArgv - The command line arguments, i.e., `process.argv`.\n * @param yargsArgv - The processed `yargs` arguments.\n * @param yargsInstance - An instance of `yargs`.\n */\nexport function applyConfig(\n snapConfig: SnapConfig,\n processArgv: string[],\n yargsArgv: Arguments,\n yargsInstance: typeof yargs,\n): void {\n // Instances of yargs has a number of undocumented functions, including\n // getOptions. This function returns an object with properties \"key\" and\n // \"alias\", which specify the options associated with the current command and\n // their aliases, respectively.\n //\n // We leverage this to ensure that the config is only applied to args that are\n // valid for the current command, and that weren't specified by the user on\n // the command line.\n //\n // If we set args that aren't valid for the current command, yargs will error\n // during validation.\n const { alias: aliases, key: options } = (\n yargsInstance as any\n ).getOptions() as {\n alias: Record<string, string[]>;\n key: Record<string, unknown>;\n };\n\n const parsedProcessArgv = yargsParse(processArgv, {\n alias: aliases,\n }) as Record<string, unknown>;\n delete parsedProcessArgv._; // irrelevant yargs parser artifact\n\n const commandOptions = new Set(Object.keys(options));\n\n const shouldSetArg = (key: string): boolean => {\n return commandOptions.has(key) && !hasProperty(parsedProcessArgv, key);\n };\n\n const cfg: Record<string, unknown> = snapConfig.cliOptions || {};\n for (const key of Object.keys(cfg)) {\n if (hasProperty(builders, key)) {\n if (shouldSetArg(key)) {\n yargsArgv[key] = cfg[key];\n }\n } else {\n logError(\n `Error: Encountered unrecognized config property \"options.${key}\" in config file \"${CONFIG_FILE}\". Remove the property and try again.`,\n );\n process.exit(1);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"snap-config.js","sourceRoot":"","sources":["../../src/utils/snap-config.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'path';\nimport { hasProperty } from '@metamask/utils';\nimport type browserify from 'browserify';\nimport { Arguments } from 'yargs';\nimport yargsParse from 'yargs-parser';\nimport yargs from 'yargs/yargs';\nimport { object, optional, func, Infer, is } from 'superstruct';\nimport builders from '../builders';\nimport { CONFIG_FILE, logError } from './misc';\n\nexport type BundleCustomizer = (bundler: browserify.BrowserifyObject) => void;\n\nexport const SnapConfigStruct = object({\n cliOptions: optional(object()),\n bundlerCustomizer: optional(func()),\n});\n\nexport type SnapConfig = Omit<\n Infer<typeof SnapConfigStruct>,\n 'bundlerCustomizer'\n> & {\n bundlerCustomizer?: BundleCustomizer;\n};\n\n/**\n * Check if the given value is a {@link SnapConfig} object. Note that this\n * function does not check the validity of the `bundleCustomizer` property, as\n * it is not possible to check the validity of a function in JavaScript.\n *\n * @param value - The value to check.\n * @returns `true` if the value is a valid {@link SnapConfig} object, `false`\n * otherwise.\n */\nexport function isSnapConfig(value: unknown): value is SnapConfig {\n return is(value, SnapConfigStruct);\n}\n\nlet snapConfigCache: SnapConfig | undefined;\n\n/**\n * Attempt to load the snap config file (`snap.config.js`). By default will use\n * the cached config, if it was loaded before, and `cached` is `true`. If the\n * config file is not found, or the config is invalid, this function will kill\n * the process.\n *\n * @param cached - Whether to use the cached config. Defaults to `true`.\n * @returns The snap config.\n */\nexport function loadConfig(cached = true): SnapConfig {\n if (snapConfigCache !== undefined && cached === true) {\n return snapConfigCache;\n }\n\n let config: any;\n try {\n // eslint-disable-next-line node/global-require, import/no-dynamic-require, @typescript-eslint/no-require-imports\n config = require(path.resolve(process.cwd(), CONFIG_FILE));\n } catch (err: any) {\n if (err.code === 'MODULE_NOT_FOUND') {\n snapConfigCache = {};\n return snapConfigCache;\n }\n logError(`Error during parsing of ${CONFIG_FILE}`, err);\n return process.exit(1);\n }\n\n if (!isSnapConfig(config)) {\n logError(\n `Can't validate ${CONFIG_FILE}. Ensure it's a proper javascript file and abides with the structure of a snap configuration file`,\n );\n return process.exit(1);\n }\n snapConfigCache = config;\n return config;\n}\n\n// Note that the below function is necessary because yargs' .config() function\n// leaves much to be desired.\n//\n// In particular, it will set all properties included in the config file\n// regardless of the command, which fails during validation.\n\n/**\n * Attempts to read configuration options for package.json and the config file,\n * and apply them to argv if they weren't already set.\n *\n * Arguments are only set per the snap-cli config file if they were not specified\n * on the command line.\n *\n * @param snapConfig - The snap config.\n * @param processArgv - The command line arguments, i.e., `process.argv`.\n * @param yargsArgv - The processed `yargs` arguments.\n * @param yargsInstance - An instance of `yargs`.\n */\nexport function applyConfig(\n snapConfig: SnapConfig,\n processArgv: string[],\n yargsArgv: Arguments,\n yargsInstance: typeof yargs,\n): void {\n // Instances of yargs has a number of undocumented functions, including\n // getOptions. This function returns an object with properties \"key\" and\n // \"alias\", which specify the options associated with the current command and\n // their aliases, respectively.\n //\n // We leverage this to ensure that the config is only applied to args that are\n // valid for the current command, and that weren't specified by the user on\n // the command line.\n //\n // If we set args that aren't valid for the current command, yargs will error\n // during validation.\n const { alias: aliases, key: options } = (\n yargsInstance as any\n ).getOptions() as {\n alias: Record<string, string[]>;\n key: Record<string, unknown>;\n };\n\n const parsedProcessArgv = yargsParse(processArgv, {\n alias: aliases,\n }) as Record<string, unknown>;\n delete parsedProcessArgv._; // irrelevant yargs parser artifact\n\n const commandOptions = new Set(Object.keys(options));\n\n const shouldSetArg = (key: string): boolean => {\n return commandOptions.has(key) && !hasProperty(parsedProcessArgv, key);\n };\n\n const cfg: Record<string, unknown> = snapConfig.cliOptions || {};\n for (const key of Object.keys(cfg)) {\n if (hasProperty(builders, key)) {\n if (shouldSetArg(key)) {\n yargsArgv[key] = cfg[key];\n }\n } else {\n logError(\n `Error: Encountered unrecognized config property \"options.${key}\" in config file \"${CONFIG_FILE}\". Remove the property and try again.`,\n );\n process.exit(1);\n }\n }\n}\n"]}