-
-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathinfer.ts
195 lines (171 loc) · 5.36 KB
/
infer.ts
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
import getPackageInfo, {
GetPackageInfoError,
GetPackageInfoResult,
GetPackageInfoResultSourceItem,
} from 'get-package-info';
import parseAuthor from 'parse-author';
import path from 'path';
import resolve, { AsyncOpts } from 'resolve';
import { debug } from './common';
import { Options, SupportedPlatform } from './types';
function isMissingRequiredProperty(props: string[]) {
return props.some(
(prop) => prop === 'productName' || prop === 'dependencies.electron',
);
}
function errorMessageForProperty(prop: string) {
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/packager/main/interfaces/Options.html#${hash}\n`
);
}
function resolvePromise(id: string, options: AsyncOpts) {
return new Promise<[string | undefined, { version: string }]>(
// eslint-disable-next-line promise/param-names
(accept, reject) => {
resolve(id, options, (err, mainPath, pkg) => {
if (err) {
/* istanbul ignore next */
reject(err);
} else {
accept([mainPath as string | undefined, pkg as { version: string }]);
}
});
},
);
}
async function getVersion(
opts: Options,
electronProp: GetPackageInfoResultSourceItem,
) {
const [, packageName] = electronProp.prop.split('.');
const src = electronProp.src;
const pkg = (
await resolvePromise(packageName, { basedir: path.dirname(src) })
)[1];
debug(`Inferring target Electron version from ${packageName} in ${src}`);
opts.electronVersion = pkg.version;
}
async function handleMetadata(
opts: Options,
result: GetPackageInfoResult,
): Promise<void> {
if (result.values.productName) {
debug(
`Inferring application name from ${result.source.productName.prop} in ${result.source.productName.src}`,
);
opts.name = result.values.productName as string;
}
if (result.values.version) {
debug(`Inferring appVersion from version in ${result.source.version.src}`);
opts.appVersion = result.values.version as string;
}
if (result.values.author && !opts.win32metadata) {
opts.win32metadata = {};
}
if (result.values.author) {
const author = result.values.author as string | { name: string };
debug(
`Inferring win32metadata.CompanyName from author in ${result.source.author.src}`,
);
if (typeof author === 'string') {
opts.win32metadata!.CompanyName = parseAuthor(author).name;
} else if (author.name) {
opts.win32metadata!.CompanyName = 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: Options, err: GetPackageInfoError) {
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);
}
}
export async function getMetadataFromPackageJSON(
platforms: SupportedPlatform[],
opts: Options,
dir: string,
): Promise<void> {
const props: Array<string | string[]> = [];
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',
]);
}
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 (e) {
const err = e as GetPackageInfoError;
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;
}
}