nw-builder 4.2.8 → 4.3.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.
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Steffen Müller
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nw-builder",
3
- "version": "4.2.8",
3
+ "version": "4.3.1",
4
4
  "description": "Build NW.js desktop applications for MacOS, Windows and Linux.",
5
5
  "keywords": [
6
6
  "NW.js",
@@ -41,7 +41,7 @@
41
41
  "scripts": {
42
42
  "fmt": "prettier --write \"./**/*.{css,html,js,json,md,yml}\"",
43
43
  "lnt": "eslint --config=cfg/eslint.config.cjs --fix src",
44
- "doc:api": "jsdoc2md ./src/index.js > ./doc/api.md && jsdoc2md ./src/bld/linuxCfg.js > ./doc/api-nux.md && jsdoc2md ./src/bld/winCfg.js > ./doc/api-win.md",
44
+ "doc:api": "jsdoc2md ./src/index.js > ./doc/api.md && jsdoc2md ./src/bld/linuxCfg.js > ./doc/api-nux.md && jsdoc2md ./src/bld/winCfg.js > ./doc/api-win.md && jsdoc2md ./src/bld/osxCfg.js > ./doc/api-osx.md",
45
45
  "doc:dev": "vitepress dev doc",
46
46
  "doc:bld": "vitepress build doc",
47
47
  "test:unit": "node --test-reporter=spec --test test/unit/index.js",
@@ -49,14 +49,14 @@
49
49
  "test:demo": "cd test/fixture && node demo.js"
50
50
  },
51
51
  "devDependencies": {
52
- "eslint": "^8.43.0",
52
+ "eslint": "^8.44.0",
53
53
  "eslint-config-tjw-jsdoc": "^1.0.3",
54
54
  "gh-pages": "^5.0.0",
55
55
  "jsdoc": "^4.0.2",
56
56
  "jsdoc-to-markdown": "^8.0.0",
57
57
  "prettier": "^2.8.8",
58
58
  "selenium-webdriver": "^4.10.0",
59
- "vitepress": "^1.0.0-beta.3"
59
+ "vitepress": "^1.0.0-beta.4"
60
60
  },
61
61
  "dependencies": {
62
62
  "cli-progress": "^3.12.0",
package/src/bld/build.js CHANGED
@@ -93,8 +93,15 @@ export const build = async (
93
93
  break;
94
94
  }
95
95
 
96
- if (zip === true || zip === "zip") {
97
- await compressing.zip.compressDir(outDir, `${outDir}.zip`);
96
+ if (zip !== false) {
97
+ if (zip === true || zip === "zip") {
98
+ await compressing.zip.compressDir(outDir, `${outDir}.zip`);
99
+ } else if (zip === "tar") {
100
+ await compressing.tar.compressDir(outDir, `${outDir}.tar`);
101
+ } else if (zip === "tgz") {
102
+ await compressing.tgz.compressDir(outDir, `${outDir}.tgz`);
103
+ }
104
+
98
105
  await rm(outDir, { recursive: true, force: true });
99
106
  }
100
107
  };
@@ -5,6 +5,7 @@ import { log } from "../log.js";
5
5
 
6
6
  /**
7
7
  * @typedef {object} LinuxRc Linux configuration options
8
+ * @typedef {string} name Name of the application
8
9
  * @property {string} genericName Generic name of the application
9
10
  * @property {boolean} noDisplay If true the application is not displayed
10
11
  * @property {string} comment Tooltip for the entry, for example "View sites on the Internet".
package/src/bld/osxCfg.js CHANGED
@@ -1,13 +1,28 @@
1
1
  import { platform } from "node:process";
2
- import fs from "node:fs/promises";
3
- import path from "node:path";
2
+ import { copyFile, rename, readFile, writeFile } from "node:fs/promises";
3
+ import { resolve } from "node:path";
4
4
 
5
5
  import plist from "plist";
6
6
 
7
7
  import { log } from "../log.js";
8
8
 
9
+ /**
10
+ * @typedef {object} OsxRc OSX resource configuration options
11
+ * @property {string} name The name of the application
12
+ * @property {string} icon The path to the icon file. It should be a .icns file.
13
+ * @property {string} LSApplicationCategoryType The category that best describes your app for the App Store.
14
+ * @property {string} CFBundleIdentifier A unique identifier for a bundle usually in reverse DNS format.
15
+ * @property {string} CFBundleName A user-visible short name for the bundle.
16
+ * @property {string} CFBundleDisplayName The user-visible name for the bundle.
17
+ * @property {string} CFBundleSpokenName A replacement for the app name in text-to-speech operations.
18
+ * @property {string} CFBundleVersion The version of the build that identifies an iteration of the bundle.
19
+ * @property {string} CFBundleShortVersionString The release or version number of the bundle.
20
+ * @property {string} NSHumanReadableCopyright A human-readable copyright notice for the bundle.
21
+ */
22
+
9
23
  /**
10
24
  * OSX specific configuration steps
25
+ * https://developer.apple.com/documentation/bundleresources/information_property_list
11
26
  *
12
27
  * @param {object} app Resource configuration options for MacOS
13
28
  * @param {string} outDir The directory to hold build artifacts
@@ -19,38 +34,36 @@ const setOsxConfig = async (app, outDir) => {
19
34
  "MacOS apps built on Windows platform do not preserve all file permissions. See #716"
20
35
  );
21
36
  }
37
+
22
38
  try {
23
- const outApp = path.resolve(outDir, `${app.name}.app`);
24
- await fs.rename(path.resolve(outDir, "nwjs.app"), outApp);
39
+ const outApp = resolve(outDir, `${app.name}.app`);
40
+ await rename(resolve(outDir, "nwjs.app"), outApp);
41
+ if (app.icon !== undefined) {
42
+ await copyFile(
43
+ resolve(app.icon),
44
+ resolve(outApp, "Contents", "Resources", "app.icns")
45
+ );
46
+ }
25
47
 
26
- // Rename CFBundleDisplayName in Contents/Info.plist
27
- const contentsInfoPlistPath = path.resolve(outApp, "Contents/Info.plist");
28
- const contentsInfoPlistJson = plist.parse(
29
- await fs.readFile(contentsInfoPlistPath, "utf-8")
30
- );
31
- contentsInfoPlistJson.CFBundleDisplayName = app.name;
32
- const contentsInfoPlist = plist.build(contentsInfoPlistJson);
33
- await fs.writeFile(contentsInfoPlistPath, contentsInfoPlist);
34
-
35
- // Rename CFBundleDisplayName in Contents/Resources/en.lproj/InfoPlist.strings
36
- const contentsInfoPlistStringsPath = path.resolve(
37
- outApp,
38
- "Contents/Resources/en.lproj/InfoPlist.strings"
39
- );
40
- const contentsInfoPlistStrings = await fs.readFile(
41
- contentsInfoPlistStringsPath,
42
- "utf-8"
43
- );
44
- const newPlistStrings = contentsInfoPlistStrings.replace(
45
- /CFBundleGetInfoString = "nwjs /,
46
- `CFBundleGetInfoString = "${app.name} `
47
- );
48
- await fs.writeFile(contentsInfoPlistStringsPath, newPlistStrings);
48
+ const infoPlistPath = resolve(outApp, "Contents", "Info.plist");
49
+ const infoPlistJson = plist.parse(await readFile(infoPlistPath, "utf-8"));
50
+
51
+ infoPlistJson.LSApplicationCategoryType = app.LSApplicationCategoryType;
52
+ infoPlistJson.CFBundleIdentifier = app.CFBundleIdentifier;
53
+ infoPlistJson.CFBundleName = app.CFBundleName;
54
+ infoPlistJson.CFBundleDisplayName = app.CFBundleDisplayName;
55
+ infoPlistJson.CFBundleSpokenName = app.CFBundleSpokenName;
56
+ infoPlistJson.CFBundleVersion = app.CFBundleVersion;
57
+ infoPlistJson.CFBundleShortVersionString = app.CFBundleShortVersionString;
58
+ infoPlistJson.NSHumanReadableCopyright = app.NSHumanReadableCopyright;
59
+
60
+ Object.keys(infoPlistJson).forEach((option) => {
61
+ if (infoPlistJson[option] === undefined) {
62
+ delete infoPlistJson[option];
63
+ }
64
+ });
49
65
 
50
- // Add product_string property to package.json
51
- // const packageJsonPath = path.resolve(outApp, "Contents/Resources/app.nw/package.json");
52
- // app.product_string = app.name;
53
- // await fs.writeFile(packageJsonPath, JSON.stringify(app, null, 4));
66
+ await writeFile(infoPlistPath, plist.build(infoPlistJson));
54
67
  } catch (error) {
55
68
  log.error(error);
56
69
  }
package/src/bld/winCfg.js CHANGED
@@ -7,6 +7,8 @@ import { log } from "../log.js";
7
7
 
8
8
  /**
9
9
  * @typedef {object} WinRc Windows configuration options
10
+ * @property {string} name The name of the application
11
+ * @property {string} version The version of the application
10
12
  * @property {string} comments Additional information that should be displayed for diagnostic purposes.
11
13
  * @property {string} company Company that produced the file—for example, Microsoft Corporation or Standard Microsystems Corporation, Inc. This string is required.
12
14
  * @property {string} fileDescription File description to be presented to users. This string may be displayed in a list box when the user is choosing files to install. For example, Keyboard Driver for AT-Style Keyboards. This string is required.
@@ -58,7 +60,6 @@ const setWinConfig = async (app, outDir) => {
58
60
  await rename(resolve(outDir, "nw.exe"), outDirAppExe);
59
61
  await rcedit(outDirAppExe, {
60
62
  "file-version": app.version,
61
- icon: app.icon,
62
63
  "product-version": app.version,
63
64
  "version-string": versionString,
64
65
  });
package/src/index.d.ts CHANGED
@@ -15,6 +15,7 @@ type Options = {
15
15
  cli: boolean,
16
16
  ffmpeg: boolean,
17
17
  glob: boolean,
18
+ logLevel: "error" | "warn" | "info" | "debug"
18
19
  };
19
20
 
20
21
  declare function nwbuild(options: Options): Promise<unknown>;
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { mkdir, rm } from "node:fs/promises";
2
2
  import { resolve } from "node:path";
3
+ import { arch, platform, version } from "node:process";
3
4
 
4
5
  import { decompress } from "./get/decompress.js";
5
6
  import { download } from "./get/download.js";
@@ -13,9 +14,8 @@ import { getFiles } from "./util/files.js";
13
14
  import { getVersionManifest } from "./util/versionManifest.js";
14
15
  import { parse } from "./util/parse.js";
15
16
  import { validate } from "./util/validate.js";
16
- import { xattr } from "./util/xattr.js";
17
17
 
18
- import { log } from "./log.js";
18
+ import { log, setLogLevel } from "./log.js";
19
19
 
20
20
  /**
21
21
  * @typedef {object} Options Configuration options
@@ -31,10 +31,11 @@ import { log } from "./log.js";
31
31
  * @property {"https://nwjs.io/versions" | string} [manifestUrl="https://nwjs.io/versions"] URI to download manifest from
32
32
  * @property {object} app Refer to Linux/Windows Specific Options under Getting Started in the docs
33
33
  * @property {boolean} [cache=true] If true the existing cache is used. Otherwise it removes and redownloads it.
34
- * @property {boolean} [zip=false] If true the outDir directory is zipped
34
+ * @property {boolean | "zip" | "tar" | "tgz"} [zip=false] If true, "zip", "tar" or "tgz" the outDir directory is compressed.
35
35
  * @property {boolean} [cli=false] If true the CLI is used to glob srcDir and parse other options
36
36
  * @property {boolean} [ffmpeg=false] If true the chromium ffmpeg is replaced by community version
37
37
  * @property {boolean} [glob=true] If true globbing is enabled
38
+ * @property {"error" | "warn" | "info" | "debug"} [logLevel="info"] Specified log level.
38
39
  */
39
40
 
40
41
  /**
@@ -92,9 +93,18 @@ const nwbuild = async (options) => {
92
93
 
93
94
  await validate(options, releaseInfo);
94
95
 
96
+ setLogLevel(options.logLevel);
97
+
95
98
  // Remove leading "v" from version string
96
99
  options.version = releaseInfo.version.slice(1);
97
100
 
101
+ if (options.logLevel === "debug") {
102
+ log.debug(`Platform: ${platform}`);
103
+ log.debug(`Archicture: ${arch}`);
104
+ log.debug(`Node Version: ${version}`);
105
+ log.debug(`NW.js Version: ${options.version}\n`);
106
+ }
107
+
98
108
  // Variable to store nwDir file path
99
109
  nwDir = resolve(
100
110
  options.cacheDir,
@@ -171,8 +181,6 @@ const nwbuild = async (options) => {
171
181
  }
172
182
  }
173
183
 
174
- await xattr(options.platform, options.arch, nwDir);
175
-
176
184
  // Downloading binaries is required for run and build modes
177
185
  // If mode is get, exit function since we have gotten the binaries
178
186
  if (options.mode === "get") {
package/src/log.js CHANGED
@@ -2,11 +2,11 @@ import { createLogger, format, transports } from "winston";
2
2
 
3
3
  const { combine, timestamp, printf } = format;
4
4
 
5
- const customFormat = printf(({ level, message, timestamp }) => {
6
- return `[ ${level.toUpperCase()} ] ${timestamp} ${message}`;
5
+ const customFormat = printf(({ level, message }) => {
6
+ return `[ ${level.toUpperCase()} ] ${message}`;
7
7
  });
8
8
 
9
- export const log = createLogger({
9
+ export let log = createLogger({
10
10
  format: combine(timestamp(), customFormat),
11
11
  transports: [
12
12
  new transports.Console({
@@ -15,10 +15,18 @@ export const log = createLogger({
15
15
  ],
16
16
  });
17
17
 
18
- // if (process.env.NODE_ENV !== "production") {
19
- // log.add(
20
- // new transports.Console({
21
- // level: "debug",
22
- // }),
23
- // );
24
- // }
18
+ /**
19
+ * Sets the log level
20
+ *
21
+ * @param {import("./index.js").Options.logLevel} level Log level
22
+ */
23
+ export function setLogLevel(level) {
24
+ log = createLogger({
25
+ format: combine(timestamp(), customFormat),
26
+ transports: [
27
+ new transports.Console({
28
+ level: level,
29
+ }),
30
+ ],
31
+ });
32
+ }
package/src/util/parse.js CHANGED
@@ -24,6 +24,7 @@ export const parse = async (options, pkg) => {
24
24
  options.cacheDir = options.cacheDir ?? "./cache";
25
25
  options.cache = options.cache ?? true;
26
26
  options.ffmpeg = options.ffmpeg ?? false;
27
+ options.logLevel = options.logLevel ?? "info";
27
28
 
28
29
  if (options.mode === "get") {
29
30
  return { ...options };
@@ -42,15 +43,14 @@ export const parse = async (options, pkg) => {
42
43
 
43
44
  options.app = options.app ?? {};
44
45
  options.app.name = options.app.name ?? pkg.name;
46
+ options.app.icon = options.app.icon ?? undefined;
45
47
 
46
- // TODO: move this out to
48
+ // TODO(#737): move this out
47
49
  if (options.platform === "linux") {
48
50
  // linux desktop entry file configurations options
49
- options.app.name = options.app.name ?? pkg.name;
50
51
  options.app.genericName = options.app.genericName ?? undefined;
51
52
  options.app.noDisplay = options.app.noDisplay ?? undefined;
52
53
  options.app.comment = options.app.comment ?? undefined;
53
- options.app.icon = options.app.icon ?? undefined;
54
54
  options.app.hidden = options.app.hidden ?? undefined;
55
55
  options.app.onlyShowIn = options.app.onlyShowIn ?? undefined;
56
56
  options.app.notShowIn = options.app.notShowIn ?? undefined;
@@ -72,6 +72,7 @@ export const parse = async (options, pkg) => {
72
72
  }
73
73
  if (options.platform === "win") {
74
74
  // windows configuration options
75
+ options.app.version = options.app.version ?? pkg.version;
75
76
  options.app.comments = options.app.comments ?? undefined;
76
77
  options.app.company = options.app.company ?? pkg.author;
77
78
  options.app.fileDescription =
@@ -87,5 +88,22 @@ export const parse = async (options, pkg) => {
87
88
  options.app.specialBuild = options.app.specialBuild ?? undefined;
88
89
  }
89
90
 
91
+ if (options.platform === "osx") {
92
+ options.app.LSApplicationCategoryType =
93
+ options.app.LSApplicationCategoryType ?? undefined;
94
+ options.app.CFBundleIdentifier =
95
+ options.app.CFBundleIdentifier ?? options.app.name;
96
+ options.app.CFBundleName = options.app.CFBundleName ?? pkg.name;
97
+ options.app.CFBundleDisplayName =
98
+ options.app.CFBundleDisplayName ?? pkg.name;
99
+ options.app.CFBundleSpokenName = options.app.CFBundleSpokenName ?? pkg.name;
100
+ options.app.CFBundleShortVersionString =
101
+ options.app.CFBundleVersion ?? pkg.version;
102
+ options.app.CFBundleVersion =
103
+ options.app.CFBundleShortVersionString ?? pkg.version;
104
+ options.app.NSHumanReadableCopyright =
105
+ options.app.NSHumanReadableCopyright ?? undefined;
106
+ }
107
+
90
108
  return { ...options };
91
109
  };
@@ -3,9 +3,9 @@ import { readdir } from "node:fs/promises";
3
3
  /**
4
4
  * Validate options
5
5
  *
6
- * @param {import("../../index.js").OPTIONS} options Options
7
- * @param {object} releaseInfo Version specific NW release info
8
- * @return {Promise<undefined>} Return undefined if options are valid
6
+ * @param {import("../index.js").Options} options Options
7
+ * @param {object} releaseInfo Version specific NW release info
8
+ * @return {Promise<undefined>} Return undefined if options are valid
9
9
  * @throws {Error} Throw error if options are invalid
10
10
  */
11
11
  export const validate = async (options, releaseInfo) => {
@@ -47,6 +47,17 @@ export const validate = async (options, releaseInfo) => {
47
47
  );
48
48
  }
49
49
 
50
+ if (
51
+ options.logLevel !== "error" &&
52
+ options.logLevel !== "warn" &&
53
+ options.logLevel !== "info" &&
54
+ options.logLevel !== "debug"
55
+ ) {
56
+ throw new Error(
57
+ "Expected 'error', 'warn', 'info' or 'debug'. Got " + options.logLevel
58
+ );
59
+ }
60
+
50
61
  if (options.mode === "get") {
51
62
  return undefined;
52
63
  }
package/src/util/xattr.js DELETED
@@ -1,30 +0,0 @@
1
- import { exec } from "node:child_process";
2
- import { resolve } from "node:path";
3
-
4
- import { log } from "../log.js";
5
-
6
- /**
7
- * Remove the quarantine attribute from the app bundle
8
- *
9
- * @param {string} platform - The platform to build for
10
- * @param {string} arch - The arch to build for
11
- * @param {string} nwDir - The path to the nw directory
12
- * @return {Promise<void>} - A promise that resolves when the attribute is removed
13
- */
14
- export const xattr = (platform, arch, nwDir) => {
15
- return new Promise((res, rej) => {
16
- if (platform === "osx" && arch === "arm64") {
17
- let app = resolve(nwDir, "nwjs.app");
18
- exec(`sudo xattr -d com.apple.quarantine ${app}`, (err, stdout) => {
19
- log.debug(stdout);
20
- if (err) {
21
- rej(err);
22
- } else {
23
- res();
24
- }
25
- });
26
- } else {
27
- res();
28
- }
29
- });
30
- };