electron-cli 0.2.6 → 0.3.0-alpha.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.
Files changed (45) hide show
  1. package/Cargo.lock +266 -0
  2. package/Cargo.toml +14 -0
  3. package/LICENSE +15 -14
  4. package/README.md +55 -52
  5. package/bin/electron-cli.js +47 -0
  6. package/package.json +35 -80
  7. package/rust-toolchain.toml +3 -0
  8. package/src/cli.rs +36 -0
  9. package/src/commands/doctor.rs +355 -0
  10. package/src/commands/inspect.rs +63 -0
  11. package/src/commands/mod.rs +3 -0
  12. package/src/commands/plan.rs +235 -0
  13. package/src/main.rs +25 -0
  14. package/src/output.rs +7 -0
  15. package/src/project.rs +320 -0
  16. package/tests/fixtures/electron-forge/package-lock.json +23 -0
  17. package/tests/fixtures/electron-forge/package.json +21 -0
  18. package/tests/fixtures/electron-forge/src/main.ts +8 -0
  19. package/.babelrc +0 -14
  20. package/.eslintrc +0 -7
  21. package/.npmignore +0 -48
  22. package/dist/cli.js +0 -15
  23. package/dist/commands/init.js +0 -247
  24. package/dist/commands/pack.js +0 -78
  25. package/dist/commands/start.js +0 -76
  26. package/dist/commands/stats.js +0 -79
  27. package/dist/init/dir.js +0 -29
  28. package/dist/init/git.js +0 -25
  29. package/dist/init/json.js +0 -31
  30. package/dist/init/npm.js +0 -17
  31. package/dist/templates/index.html +0 -13
  32. package/dist/templates/main.js +0 -55
  33. package/dist/util/change-dir.js +0 -22
  34. package/dist/util/get-versions.js +0 -53
  35. package/dist/util/pack.js +0 -17
  36. package/dist/util/path-from-cwd.js +0 -13
  37. package/dist/util/start-electron.js +0 -51
  38. package/dist/util/terminate.js +0 -25
  39. package/dist/util/version.js +0 -10
  40. package/dist/validate/check-system.js +0 -56
  41. package/dist/validate/name.js +0 -34
  42. package/gulpfile.js +0 -94
  43. package/templates/index.html +0 -13
  44. package/templates/main.js +0 -55
  45. package/yarn.lock +0 -4158
package/src/project.rs ADDED
@@ -0,0 +1,320 @@
1
+ use std::{
2
+ collections::BTreeMap,
3
+ fs,
4
+ path::{Path, PathBuf},
5
+ };
6
+
7
+ use anyhow::{Context, Result};
8
+ use camino::Utf8PathBuf;
9
+ use serde::Serialize;
10
+ use serde_json::Value;
11
+
12
+ #[derive(Debug, Serialize)]
13
+ pub struct ProjectSnapshot {
14
+ pub root: Utf8PathBuf,
15
+ pub package_json: Option<Utf8PathBuf>,
16
+ pub name: Option<String>,
17
+ pub version: Option<String>,
18
+ pub main: Option<String>,
19
+ pub package_manager: Option<String>,
20
+ pub scripts: BTreeMap<String, String>,
21
+ pub dependencies: BTreeMap<String, String>,
22
+ pub dev_dependencies: BTreeMap<String, String>,
23
+ pub optional_dependencies: BTreeMap<String, String>,
24
+ pub peer_dependencies: BTreeMap<String, String>,
25
+ pub electron_dependency: Option<String>,
26
+ pub forge_dependencies: BTreeMap<String, String>,
27
+ pub signals: Vec<String>,
28
+ }
29
+
30
+ impl ProjectSnapshot {
31
+ pub fn package_label(&self) -> Option<String> {
32
+ match (&self.name, &self.version) {
33
+ (Some(name), Some(version)) => Some(format!("{name}@{version}")),
34
+ (Some(name), None) => Some(name.clone()),
35
+ (None, Some(version)) => Some(format!("version {version}")),
36
+ (None, None) => None,
37
+ }
38
+ }
39
+
40
+ pub fn has_javascript_dependencies(&self) -> bool {
41
+ !self.dependencies.is_empty()
42
+ || !self.dev_dependencies.is_empty()
43
+ || !self.optional_dependencies.is_empty()
44
+ || !self.peer_dependencies.is_empty()
45
+ }
46
+ }
47
+
48
+ pub fn inspect(cwd: &Path) -> Result<ProjectSnapshot> {
49
+ let cwd = cwd
50
+ .canonicalize()
51
+ .with_context(|| format!("Could not resolve {}", cwd.display()))?;
52
+
53
+ let package_json_path = find_upwards(&cwd, "package.json");
54
+ let root = package_json_path
55
+ .as_ref()
56
+ .and_then(|path| path.parent().map(Path::to_path_buf))
57
+ .unwrap_or(cwd);
58
+
59
+ let package_json = match &package_json_path {
60
+ Some(path) => {
61
+ let raw = fs::read_to_string(path)
62
+ .with_context(|| format!("Could not read {}", path.display()))?;
63
+ Some(
64
+ serde_json::from_str::<Value>(&raw)
65
+ .with_context(|| format!("Could not parse {}", path.display()))?,
66
+ )
67
+ }
68
+ None => None,
69
+ };
70
+
71
+ let scripts = package_json
72
+ .as_ref()
73
+ .map(|package| string_map(package.get("scripts")))
74
+ .unwrap_or_default();
75
+
76
+ let dependencies = package_json
77
+ .as_ref()
78
+ .map(|package| string_map(package.get("dependencies")))
79
+ .unwrap_or_default();
80
+
81
+ let dev_dependencies = package_json
82
+ .as_ref()
83
+ .map(|package| string_map(package.get("devDependencies")))
84
+ .unwrap_or_default();
85
+
86
+ let optional_dependencies = package_json
87
+ .as_ref()
88
+ .map(|package| string_map(package.get("optionalDependencies")))
89
+ .unwrap_or_default();
90
+
91
+ let peer_dependencies = package_json
92
+ .as_ref()
93
+ .map(|package| string_map(package.get("peerDependencies")))
94
+ .unwrap_or_default();
95
+
96
+ let all_dependencies = merge_dependencies([
97
+ &dependencies,
98
+ &dev_dependencies,
99
+ &optional_dependencies,
100
+ &peer_dependencies,
101
+ ]);
102
+
103
+ let electron_dependency = all_dependencies.get("electron").cloned();
104
+ let forge_dependencies = all_dependencies
105
+ .iter()
106
+ .filter(|(name, _)| name.starts_with("@electron-forge/"))
107
+ .map(|(name, version)| (name.clone(), version.clone()))
108
+ .collect::<BTreeMap<_, _>>();
109
+
110
+ let package_manager = detect_package_manager(&root);
111
+ let signals = build_signals(
112
+ &scripts,
113
+ &all_dependencies,
114
+ electron_dependency.as_ref(),
115
+ &forge_dependencies,
116
+ );
117
+
118
+ Ok(ProjectSnapshot {
119
+ root: utf8_path(root)?,
120
+ package_json: package_json_path.map(utf8_path).transpose()?,
121
+ name: package_json
122
+ .as_ref()
123
+ .and_then(|package| package.get("name"))
124
+ .and_then(Value::as_str)
125
+ .map(ToOwned::to_owned),
126
+ version: package_json
127
+ .as_ref()
128
+ .and_then(|package| package.get("version"))
129
+ .and_then(Value::as_str)
130
+ .map(ToOwned::to_owned),
131
+ main: package_json
132
+ .as_ref()
133
+ .and_then(|package| package.get("main"))
134
+ .and_then(Value::as_str)
135
+ .map(ToOwned::to_owned),
136
+ package_manager,
137
+ scripts,
138
+ dependencies,
139
+ dev_dependencies,
140
+ optional_dependencies,
141
+ peer_dependencies,
142
+ electron_dependency,
143
+ forge_dependencies,
144
+ signals,
145
+ })
146
+ }
147
+
148
+ fn string_map(value: Option<&Value>) -> BTreeMap<String, String> {
149
+ value
150
+ .and_then(Value::as_object)
151
+ .map(|object| {
152
+ object
153
+ .iter()
154
+ .filter_map(|(key, value)| {
155
+ value.as_str().map(|value| (key.clone(), value.to_string()))
156
+ })
157
+ .collect()
158
+ })
159
+ .unwrap_or_default()
160
+ }
161
+
162
+ fn merge_dependencies<'a>(
163
+ groups: impl IntoIterator<Item = &'a BTreeMap<String, String>>,
164
+ ) -> BTreeMap<String, String> {
165
+ let mut merged = BTreeMap::new();
166
+
167
+ for group in groups {
168
+ for (name, version) in group {
169
+ merged.insert(name.clone(), version.clone());
170
+ }
171
+ }
172
+
173
+ merged
174
+ }
175
+
176
+ fn detect_package_manager(root: &Path) -> Option<String> {
177
+ [
178
+ ("package-lock.json", "npm"),
179
+ ("npm-shrinkwrap.json", "npm"),
180
+ ("pnpm-lock.yaml", "pnpm"),
181
+ ("yarn.lock", "yarn"),
182
+ ("bun.lock", "bun"),
183
+ ("bun.lockb", "bun"),
184
+ ]
185
+ .iter()
186
+ .find_map(|(file, manager)| root.join(file).exists().then(|| manager.to_string()))
187
+ }
188
+
189
+ fn build_signals(
190
+ scripts: &BTreeMap<String, String>,
191
+ dependencies: &BTreeMap<String, String>,
192
+ electron_dependency: Option<&String>,
193
+ forge_dependencies: &BTreeMap<String, String>,
194
+ ) -> Vec<String> {
195
+ let mut signals = Vec::new();
196
+
197
+ if electron_dependency.is_some() {
198
+ signals.push("electron dependency declared".to_string());
199
+ }
200
+
201
+ if !forge_dependencies.is_empty() {
202
+ signals.push("electron forge dependency declared".to_string());
203
+ }
204
+
205
+ if dependencies.contains_key("vite") || dependencies.contains_key("@vitejs/plugin-react") {
206
+ signals.push("vite tooling detected".to_string());
207
+ }
208
+
209
+ if dependencies.contains_key("typescript") {
210
+ signals.push("typescript tooling detected".to_string());
211
+ }
212
+
213
+ if scripts
214
+ .values()
215
+ .any(|script| script.contains("electron") || script.contains("electron-forge"))
216
+ {
217
+ signals.push("electron command found in package scripts".to_string());
218
+ }
219
+
220
+ signals
221
+ }
222
+
223
+ fn find_upwards(start: &Path, file_name: &str) -> Option<PathBuf> {
224
+ let mut current = Some(start);
225
+
226
+ while let Some(path) = current {
227
+ let candidate = path.join(file_name);
228
+ if candidate.exists() {
229
+ return Some(candidate);
230
+ }
231
+
232
+ current = path.parent();
233
+ }
234
+
235
+ None
236
+ }
237
+
238
+ fn utf8_path(path: PathBuf) -> Result<Utf8PathBuf> {
239
+ Utf8PathBuf::from_path_buf(path).map_err(|path| {
240
+ anyhow::anyhow!(
241
+ "Path contains invalid UTF-8 and cannot be represented in JSON: {}",
242
+ path.display()
243
+ )
244
+ })
245
+ }
246
+
247
+ #[cfg(test)]
248
+ mod tests {
249
+ use super::*;
250
+
251
+ #[test]
252
+ fn maps_string_values_only() {
253
+ let value = serde_json::json!({
254
+ "electron": "^30.0.0",
255
+ "bad": false
256
+ });
257
+
258
+ let map = string_map(Some(&value));
259
+
260
+ assert_eq!(map.get("electron"), Some(&"^30.0.0".to_string()));
261
+ assert!(!map.contains_key("bad"));
262
+ }
263
+
264
+ #[test]
265
+ fn builds_electron_signals() {
266
+ let mut scripts = BTreeMap::new();
267
+ scripts.insert("start".to_string(), "electron-forge start".to_string());
268
+
269
+ let mut dependencies = BTreeMap::new();
270
+ dependencies.insert("electron".to_string(), "^30.0.0".to_string());
271
+ dependencies.insert("@electron-forge/cli".to_string(), "^7.0.0".to_string());
272
+ dependencies.insert("typescript".to_string(), "^5.0.0".to_string());
273
+
274
+ let forge = dependencies
275
+ .iter()
276
+ .filter(|(name, _)| name.starts_with("@electron-forge/"))
277
+ .map(|(name, version)| (name.clone(), version.clone()))
278
+ .collect::<BTreeMap<_, _>>();
279
+
280
+ let signals = build_signals(
281
+ &scripts,
282
+ &dependencies,
283
+ dependencies.get("electron"),
284
+ &forge,
285
+ );
286
+
287
+ assert!(signals.contains(&"electron dependency declared".to_string()));
288
+ assert!(signals.contains(&"electron forge dependency declared".to_string()));
289
+ assert!(signals.contains(&"typescript tooling detected".to_string()));
290
+ assert!(signals.contains(&"electron command found in package scripts".to_string()));
291
+ }
292
+
293
+ #[test]
294
+ fn inspects_electron_forge_fixture_from_nested_directory() {
295
+ let fixture = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/electron-forge");
296
+ let nested = fixture.join("src");
297
+
298
+ let snapshot = inspect(&nested).expect("fixture should inspect");
299
+
300
+ assert_eq!(snapshot.name.as_deref(), Some("fixture-electron-forge-app"));
301
+ assert_eq!(snapshot.version.as_deref(), Some("0.1.0"));
302
+ assert_eq!(snapshot.main.as_deref(), Some("src/main.ts"));
303
+ assert_eq!(snapshot.package_manager.as_deref(), Some("npm"));
304
+ assert_eq!(snapshot.electron_dependency.as_deref(), Some("^31.0.0"));
305
+ assert_eq!(
306
+ snapshot
307
+ .forge_dependencies
308
+ .get("@electron-forge/cli")
309
+ .map(String::as_str),
310
+ Some("^7.0.0")
311
+ );
312
+ assert!(snapshot.has_javascript_dependencies());
313
+ assert!(snapshot
314
+ .signals
315
+ .contains(&"electron forge dependency declared".to_string()));
316
+ assert!(snapshot
317
+ .signals
318
+ .contains(&"electron command found in package scripts".to_string()));
319
+ }
320
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "fixture-electron-forge-app",
3
+ "version": "0.1.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "fixture-electron-forge-app",
9
+ "version": "0.1.0",
10
+ "dependencies": {
11
+ "electron-squirrel-startup": "^1.0.1"
12
+ },
13
+ "devDependencies": {
14
+ "@electron-forge/cli": "^7.0.0",
15
+ "@electron-forge/maker-squirrel": "^7.0.0",
16
+ "@electron-forge/plugin-vite": "^7.0.0",
17
+ "electron": "^31.0.0",
18
+ "typescript": "^5.5.0",
19
+ "vite": "^5.0.0"
20
+ }
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "fixture-electron-forge-app",
3
+ "version": "0.1.0",
4
+ "main": "src/main.ts",
5
+ "scripts": {
6
+ "start": "electron-forge start",
7
+ "package": "electron-forge package",
8
+ "make": "electron-forge make"
9
+ },
10
+ "dependencies": {
11
+ "electron-squirrel-startup": "^1.0.1"
12
+ },
13
+ "devDependencies": {
14
+ "@electron-forge/cli": "^7.0.0",
15
+ "@electron-forge/maker-squirrel": "^7.0.0",
16
+ "@electron-forge/plugin-vite": "^7.0.0",
17
+ "electron": "^31.0.0",
18
+ "typescript": "^5.5.0",
19
+ "vite": "^5.0.0"
20
+ }
21
+ }
@@ -0,0 +1,8 @@
1
+ import { app, BrowserWindow } from "electron";
2
+
3
+ function createWindow() {
4
+ const window = new BrowserWindow({ width: 800, height: 600 });
5
+ window.loadURL("about:blank");
6
+ }
7
+
8
+ app.whenReady().then(createWindow);
package/.babelrc DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "presets": ["stage-2","es2015"],
3
- "plugins": [
4
- "transform-runtime",
5
- "syntax-async-functions",
6
- "transform-async-to-generator",
7
- "transform-object-rest-spread"
8
- ],
9
- "env": {
10
- "test": {
11
- "plugins": [ "istanbul" ]
12
- }
13
- }
14
- }
package/.eslintrc DELETED
@@ -1,7 +0,0 @@
1
- {
2
- "extends": ["airbnb-base","standard"],
3
- "rules": {
4
- "complexity": [1, { "max": 5 }],
5
- "semi": "error"
6
- }
7
- }
package/.npmignore DELETED
@@ -1,48 +0,0 @@
1
- # Logs
2
- logs
3
- *.log
4
- npm-debug.log*
5
-
6
- # Runtime data
7
- pids
8
- *.pid
9
- *.seed
10
- *.pid.lock
11
-
12
- # Directory for instrumented libs generated by jscoverage/JSCover
13
- lib-cov
14
-
15
- # Coverage directory used by tools like istanbul
16
- coverage
17
-
18
- # nyc test coverage
19
- .nyc_output
20
-
21
- # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
22
- .grunt
23
-
24
- # node-waf configuration
25
- .lock-wscript
26
-
27
- # Compiled binary addons (http://nodejs.org/api/addons.html)
28
- build/Release
29
-
30
- # Dependency directories
31
- node_modules
32
- jspm_packages
33
-
34
- # Optional npm cache directory
35
- .npm
36
-
37
- # Optional eslint cache
38
- .eslintcache
39
-
40
- # Optional REPL history
41
- .node_repl_history
42
-
43
- .DS_Store
44
-
45
- # dev only files
46
- src
47
- notes
48
- test
package/dist/cli.js DELETED
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- var _yargs = require('yargs');
5
-
6
- var _yargs2 = _interopRequireDefault(_yargs);
7
-
8
- require('./util/terminate');
9
-
10
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
-
12
- // Provide a title to the process in `ps`
13
- process.title = 'electron-cli';
14
-
15
- _yargs2.default.commandDir('./commands').demand(1).help('h').alias('h', 'help').argv;