1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
'use strict'
const debug = require('debug')('electron-packager')
const getPackageInfo = require('get-package-info')
const parseAuthor = require('parse-author')
const path = require('path')
const resolve = require('resolve')
const semver = require('semver')
function isMissingRequiredProperty (props) {
return props.some(prop => prop === 'productName' || prop === 'dependencies.electron')
}
function errorMessageForProperty (prop) {
let hash, propDescription
switch (prop) {
case 'productName':
hash = 'name'
propDescription = 'application name'
break
case 'dependencies.electron':
hash = 'electronversion'
propDescription = 'Electron version'
break
case 'version':
hash = 'appversion'
propDescription = 'application version'
break
/* istanbul ignore next */
default:
hash = ''
propDescription = `[Unknown Property (${prop})]`
}
return `Unable to determine ${propDescription}. Please specify an ${propDescription}\n\n` +
'For more information, please see\n' +
`https://electron.github.io/electron-packager/main/interfaces/electronpackager.options.html#${hash}\n`
}
function resolvePromise (id, options) {
// eslint-disable-next-line promise/param-names
return new Promise((accept, reject) => {
resolve(id, options, (err, mainPath, pkg) => {
if (err) {
/* istanbul ignore next */
reject(err)
} else {
accept([mainPath, pkg])
}
})
})
}
function rangeFromElectronVersion (electronVersion) {
try {
return new semver.Range(electronVersion)
} catch (error) {
return null
}
}
async function getVersion (opts, electronProp) {
const [depType, packageName] = electronProp.prop.split('.')
const src = electronProp.src
if (packageName === 'electron-prebuilt-compile') {
const electronVersion = electronProp.pkg[depType][packageName]
const versionRange = rangeFromElectronVersion(electronVersion)
if (versionRange !== null && versionRange.intersects(new semver.Range('< 1.6.5'))) {
if (!/^\d+\.\d+\.\d+/.test(electronVersion)) {
// electron-prebuilt-compile cannot be resolved because `main` does not point
// to a valid JS file.
throw new Error('Using electron-prebuilt-compile with Electron Packager requires specifying an exact Electron version')
}
opts.electronVersion = electronVersion
return Promise.resolve()
}
}
const pkg = (await resolvePromise(packageName, { basedir: path.dirname(src) }))[1]
debug(`Inferring target Electron version from ${packageName} in ${src}`)
opts.electronVersion = pkg.version
return null
}
async function handleMetadata (opts, result) {
if (result.values.productName) {
debug(`Inferring application name from ${result.source.productName.prop} in ${result.source.productName.src}`)
opts.name = result.values.productName
}
if (result.values.version) {
debug(`Inferring appVersion from version in ${result.source.version.src}`)
opts.appVersion = result.values.version
}
if (result.values.author && !opts.win32metadata) {
opts.win32metadata = {}
}
if (result.values.author) {
debug(`Inferring win32metadata.CompanyName from author in ${result.source.author.src}`)
if (typeof result.values.author === 'string') {
opts.win32metadata.CompanyName = parseAuthor(result.values.author).name
} else if (result.values.author.name) {
opts.win32metadata.CompanyName = result.values.author.name
} else {
debug('Cannot infer win32metadata.CompanyName from author, no name found')
}
}
// eslint-disable-next-line no-prototype-builtins
if (result.values.hasOwnProperty('dependencies.electron')) {
return getVersion(opts, result.source['dependencies.electron'])
} else {
return Promise.resolve()
}
}
function handleMissingProperties (opts, err) {
const missingProps = err.missingProps.map(prop => {
return Array.isArray(prop) ? prop[0] : prop
})
if (isMissingRequiredProperty(missingProps)) {
const messages = missingProps.map(errorMessageForProperty)
debug(err.message)
err.message = messages.join('\n') + '\n'
throw err
} else {
// Missing props not required, can continue w/ partial result
return handleMetadata(opts, err.result)
}
}
module.exports = async function getMetadataFromPackageJSON (platforms, opts, dir) {
const props = []
if (!opts.name) props.push(['productName', 'name'])
if (!opts.appVersion) props.push('version')
if (!opts.electronVersion) {
props.push([
'dependencies.electron',
'devDependencies.electron',
'dependencies.electron-nightly',
'devDependencies.electron-nightly',
'dependencies.electron-prebuilt-compile',
'devDependencies.electron-prebuilt-compile',
'dependencies.electron-prebuilt',
'devDependencies.electron-prebuilt'
])
}
if (platforms.includes('win32') && !(opts.win32metadata && opts.win32metadata.CompanyName)) {
debug('Requiring author in package.json, as CompanyName was not specified for win32metadata')
props.push('author')
}
// Name and version provided, no need to infer
if (props.length === 0) return Promise.resolve()
// Search package.json files to infer name and version from
try {
const result = await getPackageInfo(props, dir)
return handleMetadata(opts, result)
} catch (err) {
if (err.missingProps) {
if (err.missingProps.length === props.length) {
debug(err.message)
err.message = `Could not locate a package.json file in "${path.resolve(opts.dir)}" or its parent directories for an Electron app with the following fields: ${err.missingProps.join(', ')}`
} else {
return handleMissingProperties(opts, err)
}
}
throw err
}
}
|