nw-builder 4.2.7 → 4.3.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.
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.7",
3
+ "version": "4.3.0",
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,24 +49,23 @@
49
49
  "test:demo": "cd test/fixture && node demo.js"
50
50
  },
51
51
  "devDependencies": {
52
- "eslint": "^8.42.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
- "prettier": "^2.8.6",
57
+ "prettier": "^2.8.8",
58
58
  "selenium-webdriver": "^4.10.0",
59
- "vitepress": "^1.0.0-beta.2"
59
+ "vitepress": "^1.0.0-beta.4"
60
60
  },
61
61
  "dependencies": {
62
- "archiver": "^5.3.1",
63
62
  "cli-progress": "^3.12.0",
64
63
  "compressing": "^1.9.0",
65
- "glob": "^10.2.7",
64
+ "glob": "^10.3.1",
66
65
  "plist": "^3.0.6",
67
66
  "rcedit": "^3.0.1",
68
- "winston": "^3.8.2",
69
- "yargs": "^17.7.1"
67
+ "winston": "^3.9.0",
68
+ "yargs": "^17.7.2"
70
69
  },
71
70
  "bin": {
72
71
  "nwbuild": "./src/cli.js"
package/src/bld/build.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import { resolve } from "node:path";
2
2
  import { cp, rm, writeFile } from "node:fs/promises";
3
3
 
4
+ import compressing from "compressing";
5
+
4
6
  import { log } from "../log.js";
5
7
 
6
- import { compress } from "./compress.js";
7
8
  import { setLinuxConfig } from "./linuxCfg.js";
8
9
  import { setOsxConfig } from "./osxCfg.js";
9
10
  import { setWinConfig } from "./winCfg.js";
@@ -92,9 +93,15 @@ export const build = async (
92
93
  break;
93
94
  }
94
95
 
95
- if (zip === true) {
96
- await compress(outDir);
97
- } else if (zip === "zip") {
98
- await compress(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
+
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,27 @@
1
1
  import { platform } from "node:process";
2
2
  import fs from "node:fs/promises";
3
- import path from "node:path";
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} LSApplicationCategoryType The category that best describes your app for the App Store.
13
+ * @property {string} CFBundleIdentifier A unique identifier for a bundle usually in reverse DNS format.
14
+ * @property {string} CFBundleName A user-visible short name for the bundle.
15
+ * @property {string} CFBundleDisplayName The user-visible name for the bundle.
16
+ * @property {string} CFBundleSpokenName A replacement for the app name in text-to-speech operations.
17
+ * @property {string} CFBundleVersion The version of the build that identifies an iteration of the bundle.
18
+ * @property {string} CFBundleShortVersionString The release or version number of the bundle.
19
+ * @property {string} NSHumanReadableCopyright A human-readable copyright notice for the bundle.
20
+ */
21
+
9
22
  /**
10
23
  * OSX specific configuration steps
24
+ * https://developer.apple.com/documentation/bundleresources/information_property_list
11
25
  *
12
26
  * @param {object} app Resource configuration options for MacOS
13
27
  * @param {string} outDir The directory to hold build artifacts
@@ -20,37 +34,31 @@ const setOsxConfig = async (app, outDir) => {
20
34
  );
21
35
  }
22
36
  try {
23
- const outApp = path.resolve(outDir, `${app.name}.app`);
24
- await fs.rename(path.resolve(outDir, "nwjs.app"), outApp);
37
+ const outApp = resolve(outDir, `${app.name}.app`);
38
+ await fs.rename(resolve(outDir, "nwjs.app"), outApp);
25
39
 
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"
40
+ const infoPlistPath = resolve(outApp, "Contents/Info.plist");
41
+ const infoPlistJson = plist.parse(
42
+ await fs.readFile(infoPlistPath, "utf-8")
39
43
  );
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);
49
44
 
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));
45
+ infoPlistJson.LSApplicationCategoryType = app.LSApplicationCategoryType;
46
+ infoPlistJson.CFBundleIdentifier = app.CFBundleIdentifier;
47
+ infoPlistJson.CFBundleName = app.CFBundleName;
48
+ infoPlistJson.CFBundleDisplayName = app.CFBundleDisplayName;
49
+ infoPlistJson.CFBundleSpokenName = app.CFBundleSpokenName;
50
+ infoPlistJson.CFBundleVersion = app.CFBundleVersion;
51
+ infoPlistJson.CFBundleShortVersionString = app.CFBundleShortVersionString;
52
+ infoPlistJson.NSHumanReadableCopyright = app.NSHumanReadableCopyright;
53
+ infoPlistJson.CFBundleIconFile = app.CFBundleIconFile;
54
+
55
+ Object.keys(infoPlistJson).forEach((option) => {
56
+ if (infoPlistJson[option] === undefined) {
57
+ delete infoPlistJson[option];
58
+ }
59
+ });
60
+
61
+ await fs.writeFile(infoPlistPath, plist.build(infoPlistJson));
54
62
  } catch (error) {
55
63
  log.error(error);
56
64
  }
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/get/remove.js CHANGED
@@ -15,15 +15,18 @@ const remove = async (platform, cacheDir, downloadUrl) => {
15
15
  try {
16
16
  if (downloadUrl === "https://dl.nwjs.io/") {
17
17
  if (platform === "linux") {
18
- await rm(resolve(cacheDir, "nw.tgz"));
18
+ await rm(resolve(cacheDir, "nw.tgz"), { recursive: true, force: true });
19
19
  } else {
20
- await rm(resolve(cacheDir, "nw.zip"));
20
+ await rm(resolve(cacheDir, "nw.zip"), { recursive: true, force: true });
21
21
  }
22
22
  } else if (
23
23
  downloadUrl ===
24
24
  "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download"
25
25
  ) {
26
- await rm(resolve(cacheDir, "ffmpeg.zip"));
26
+ await rm(resolve(cacheDir, "ffmpeg.zip"), {
27
+ recursive: true,
28
+ force: true,
29
+ });
27
30
  }
28
31
  } catch (error) {
29
32
  log.error(error);
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";
@@ -15,7 +16,7 @@ import { parse } from "./util/parse.js";
15
16
  import { validate } from "./util/validate.js";
16
17
  import { xattr } from "./util/xattr.js";
17
18
 
18
- import { log } from "./log.js";
19
+ import { log, setLogLevel } from "./log.js";
19
20
 
20
21
  /**
21
22
  * @typedef {object} Options Configuration options
@@ -31,10 +32,11 @@ import { log } from "./log.js";
31
32
  * @property {"https://nwjs.io/versions" | string} [manifestUrl="https://nwjs.io/versions"] URI to download manifest from
32
33
  * @property {object} app Refer to Linux/Windows Specific Options under Getting Started in the docs
33
34
  * @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
35
+ * @property {boolean | "zip" | "tar" | "tgz"} [zip=false] If true, "zip", "tar" or "tgz" the outDir directory is compressed.
35
36
  * @property {boolean} [cli=false] If true the CLI is used to glob srcDir and parse other options
36
37
  * @property {boolean} [ffmpeg=false] If true the chromium ffmpeg is replaced by community version
37
38
  * @property {boolean} [glob=true] If true globbing is enabled
39
+ * @property {"error" | "warn" | "info" | "debug"} [logLevel="info"] Specified log level.
38
40
  */
39
41
 
40
42
  /**
@@ -92,9 +94,18 @@ const nwbuild = async (options) => {
92
94
 
93
95
  await validate(options, releaseInfo);
94
96
 
97
+ setLogLevel(options.logLevel);
98
+
95
99
  // Remove leading "v" from version string
96
100
  options.version = releaseInfo.version.slice(1);
97
101
 
102
+ if (options.logLevel === "debug") {
103
+ log.debug(`Platform: ${platform}`);
104
+ log.debug(`Archicture: ${arch}`);
105
+ log.debug(`Node Version: ${version}`);
106
+ log.debug(`NW.js Version: ${options.version}\n`);
107
+ }
108
+
98
109
  // Variable to store nwDir file path
99
110
  nwDir = resolve(
100
111
  options.cacheDir,
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 };
@@ -43,10 +44,9 @@ export const parse = async (options, pkg) => {
43
44
  options.app = options.app ?? {};
44
45
  options.app.name = options.app.name ?? pkg.name;
45
46
 
46
- // TODO: move this out to
47
+ // TODO(#737): move this out
47
48
  if (options.platform === "linux") {
48
49
  // linux desktop entry file configurations options
49
- options.app.name = options.app.name ?? pkg.name;
50
50
  options.app.genericName = options.app.genericName ?? undefined;
51
51
  options.app.noDisplay = options.app.noDisplay ?? undefined;
52
52
  options.app.comment = options.app.comment ?? 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
  }
@@ -1,40 +0,0 @@
1
- import fs from "node:fs";
2
- import archiver from "archiver";
3
-
4
- import { log } from "../log.js";
5
-
6
- /**
7
- * Compress a out directory
8
- *
9
- * @param {string} outDir - Output directory
10
- * @param {string} type - Compression type
11
- * @return {Promise<undefined>}
12
- */
13
- const compress = (outDir, type = "zip") => {
14
- const output = fs.createWriteStream(`${outDir}.${type}`);
15
- const archive = archiver("zip");
16
-
17
- return new Promise((res, rej) => {
18
- output.on("close", () => {
19
- res();
20
- });
21
-
22
- archive.on("warning", (err) => {
23
- if (err.code === "ENOENT") {
24
- log.debug(err);
25
- } else {
26
- rej(err);
27
- }
28
- });
29
-
30
- archive.on("error", (err) => {
31
- rej(err);
32
- });
33
-
34
- archive.pipe(output);
35
- archive.directory(outDir, false);
36
- archive.finalize();
37
- });
38
- };
39
-
40
- export { compress };