1
1
import { prettyPath } from '@ionic/cli-framework/utils/format' ;
2
+ import { readPackageJsonFile } from '@ionic/cli-framework/utils/node' ;
2
3
import { readFile , writeFile } from '@ionic/utils-fs' ;
3
4
import * as Debug from 'debug' ;
4
5
import * as et from 'elementtree' ;
5
6
import * as path from 'path' ;
6
7
7
- import { ProjectIntegration , ResourcesPlatform } from '../../../definitions' ;
8
+ import { CordovaPackageJson , ProjectIntegration , ResourcesPlatform } from '../../../definitions' ;
9
+ import { isCordovaPackageJson } from '../../../guards' ;
8
10
import { failure , input , strong } from '../../color' ;
9
11
import { FatalException } from '../../errors' ;
10
12
import { shortid } from '../../utils/uuid' ;
11
13
12
14
const debug = Debug ( 'ionic:lib:integrations:cordova:config' ) ;
13
15
14
- export interface PlatformEngine {
16
+ export interface ConfiguredPlatform {
15
17
name : string ;
16
- spec : string ;
17
- [ key : string ] : string ;
18
+ spec ?: string ;
18
19
}
19
20
20
- export class ConfigXml {
21
+ export class ConfigConfig {
21
22
protected _doc ?: et . ElementTree ;
23
+ protected _pkg ?: CordovaPackageJson ;
22
24
protected _sessionid ?: string ;
23
25
protected saving = false ;
24
26
25
- constructor ( readonly filePath : string ) { }
27
+ constructor ( readonly configXmlPath : string , readonly packageJsonPath : string ) { }
26
28
27
- get doc ( ) {
29
+ get doc ( ) : et . ElementTree {
28
30
if ( ! this . _doc ) {
29
31
throw new Error ( 'No doc loaded.' ) ;
30
32
}
31
33
32
34
return this . _doc ;
33
35
}
34
36
35
- get sessionid ( ) {
37
+ get pkg ( ) : CordovaPackageJson {
38
+ if ( ! this . _pkg ) {
39
+ throw new Error ( 'No package.json loaded.' ) ;
40
+ }
41
+
42
+ return this . _pkg ;
43
+ }
44
+
45
+ get sessionid ( ) : string {
36
46
if ( ! this . _sessionid ) {
37
47
throw new Error ( 'No doc loaded.' ) ;
38
48
}
39
49
40
50
return this . _sessionid ;
41
51
}
42
52
43
- static async load ( filePath : string ) : Promise < ConfigXml > {
44
- if ( ! filePath ) {
45
- throw new Error ( 'Must supply file path .' ) ;
53
+ static async load ( configXmlPath : string , packageJsonPath : string ) : Promise < ConfigConfig > {
54
+ if ( ! configXmlPath || ! packageJsonPath ) {
55
+ throw new Error ( 'Must supply file paths for config.xml and package.json .' ) ;
46
56
}
47
57
48
- const conf = new ConfigXml ( filePath ) ;
58
+ const conf = new ConfigConfig ( configXmlPath , packageJsonPath ) ;
49
59
await conf . reload ( ) ;
50
60
51
61
return conf ;
52
62
}
53
63
54
- async reload ( ) : Promise < void > {
55
- const configFileContents = await readFile ( this . filePath , { encoding : 'utf8' } ) ;
64
+ protected async reload ( ) : Promise < void > {
65
+ const configXml = await readFile ( this . configXmlPath , { encoding : 'utf8' } ) ;
56
66
57
- if ( ! configFileContents ) {
67
+ if ( ! configXml ) {
58
68
throw new Error ( `Cannot load empty config.xml file.` ) ;
59
69
}
60
70
61
71
try {
62
- this . _doc = et . parse ( configFileContents ) ;
72
+ this . _doc = et . parse ( configXml ) ;
63
73
this . _sessionid = shortid ( ) ;
64
74
} catch ( e ) {
65
75
throw new Error ( `Cannot parse config.xml file: ${ e . stack ? e . stack : e } ` ) ;
66
76
}
77
+
78
+ const packageJson = await readPackageJsonFile ( this . packageJsonPath ) ;
79
+
80
+ if ( isCordovaPackageJson ( packageJson ) ) {
81
+ this . _pkg = packageJson ;
82
+ } else {
83
+ this . _pkg = { ...packageJson , cordova : { platforms : [ ] , plugins : { } } } ;
84
+ debug ( 'Invalid package.json for Cordova. Missing or invalid Cordova entries in %O' , this . packageJsonPath ) ;
85
+ }
67
86
}
68
87
69
88
async save ( ) : Promise < void > {
70
89
if ( ! this . saving ) {
71
90
this . saving = true ;
72
- await writeFile ( this . filePath , this . write ( ) , { encoding : 'utf8' } ) ;
91
+ await writeFile ( this . configXmlPath , this . write ( ) , { encoding : 'utf8' } ) ;
73
92
this . saving = false ;
74
93
}
75
94
}
76
95
77
- setName ( name : string ) {
96
+ setName ( name : string ) : void {
78
97
const root = this . doc . getroot ( ) ;
79
98
let nameNode = root . find ( 'name' ) ;
80
99
@@ -85,12 +104,12 @@ export class ConfigXml {
85
104
nameNode . text = name ;
86
105
}
87
106
88
- setBundleId ( bundleId : string ) {
107
+ setBundleId ( bundleId : string ) : void {
89
108
const root = this . doc . getroot ( ) ;
90
109
root . set ( 'id' , bundleId ) ;
91
110
}
92
111
93
- getBundleId ( ) {
112
+ getBundleId ( ) : string | undefined {
94
113
const root = this . doc . getroot ( ) ;
95
114
return root . get ( 'id' ) ;
96
115
}
@@ -99,7 +118,7 @@ export class ConfigXml {
99
118
* Update config.xml content src to be a dev server url. As part of this
100
119
* backup the original content src for a reset to occur at a later time.
101
120
*/
102
- writeContentSrc ( newSrc : string ) {
121
+ writeContentSrc ( newSrc : string ) : void {
103
122
const root = this . doc . getroot ( ) ;
104
123
let contentElement = root . find ( 'content' ) ;
105
124
@@ -190,25 +209,16 @@ export class ConfigXml {
190
209
return { id, name, version } ;
191
210
}
192
211
193
- getPlatformEngines ( ) : PlatformEngine [ ] {
194
- const root = this . doc . getroot ( ) ;
195
- const engines = root . findall ( 'engine' ) ;
212
+ getConfiguredPlatforms ( ) : ConfiguredPlatform [ ] {
213
+ const deps : { [ key : string ] : string | undefined ; } = { ...this . pkg . devDependencies , ...this . pkg . dependencies } ;
196
214
197
- return engines . map ( engine => this . engineElementToPlatformEngine ( engine ) ) ;
215
+ return this . pkg . cordova . platforms . map ( platform => ( {
216
+ name : platform ,
217
+ spec : deps [ `cordova-${ platform } ` ] ,
218
+ } ) ) ;
198
219
}
199
220
200
- getPlatformEngine ( platform : string ) : PlatformEngine | undefined {
201
- const root = this . doc . getroot ( ) ;
202
- const engine = root . find ( `engine[@name='${ platform } ']` ) ;
203
-
204
- if ( ! engine ) {
205
- return undefined ;
206
- }
207
-
208
- return this . engineElementToPlatformEngine ( engine ) ;
209
- }
210
-
211
- async ensurePlatformImages ( platform : string , resourcesPlatform : ResourcesPlatform ) {
221
+ ensurePlatformImages ( platform : string , resourcesPlatform : ResourcesPlatform ) : void {
212
222
const root = this . doc . getroot ( ) ;
213
223
const orientation = this . getPreference ( 'Orientation' ) || 'default' ;
214
224
@@ -253,7 +263,7 @@ export class ConfigXml {
253
263
}
254
264
}
255
265
256
- async ensureSplashScreenPreferences ( ) {
266
+ ensureSplashScreenPreferences ( ) : void {
257
267
const root = this . doc . getroot ( ) ;
258
268
259
269
let splashScreenPrefElement = root . find ( `preference[@name='SplashScreen']` ) ;
@@ -281,28 +291,28 @@ export class ConfigXml {
281
291
282
292
return contents ;
283
293
}
284
-
285
- protected engineElementToPlatformEngine ( engine : et . Element ) : PlatformEngine {
286
- const name = engine . get ( 'name' ) ;
287
- const spec = engine . get ( 'spec' ) ;
288
-
289
- return { name : name ? name : '' , spec : spec ? spec : '' , ...engine . attrib } ;
290
- }
291
294
}
292
295
293
- export async function loadConfigXml ( integration : Required < ProjectIntegration > ) : Promise < ConfigXml > {
294
- const filePath = path . resolve ( integration . root , 'config.xml' ) ;
295
- debug ( `Using config.xml: ${ filePath } ` ) ;
296
+ export async function loadCordovaConfig ( integration : Required < ProjectIntegration > ) : Promise < ConfigConfig > {
297
+ const configXmlPath = path . resolve ( integration . root , 'config.xml' ) ;
298
+ const packageJsonPath = path . resolve ( integration . root , 'package.json' ) ;
299
+
300
+ debug ( 'Loading Cordova Config (config.xml: %O, package.json: %O)' , configXmlPath , packageJsonPath ) ;
296
301
297
302
try {
298
- return await ConfigXml . load ( filePath ) ;
303
+ return await ConfigConfig . load ( configXmlPath , packageJsonPath ) ;
299
304
} catch ( e ) {
300
305
const msg = e . code === 'ENOENT'
301
- ? `Cordova ${ strong ( 'config.xml' ) } file not found.\n\nYou can re-add the Cordova integration with the following command: ${ input ( 'ionic integrations enable cordova --add' ) } `
306
+ ? (
307
+ `Could not find necessary file(s): ${ strong ( 'config.xml' ) } , ${ strong ( 'package.json' ) } .\n\n` +
308
+ ` - ${ strong ( prettyPath ( configXmlPath ) ) } \n` +
309
+ ` - ${ strong ( prettyPath ( packageJsonPath ) ) } \n\n` +
310
+ `You can re-add the Cordova integration with the following command: ${ input ( 'ionic integrations enable cordova --add' ) } `
311
+ )
302
312
: failure ( e . stack ? e . stack : e ) ;
303
313
304
314
throw new FatalException (
305
- `Cannot load ${ strong ( prettyPath ( filePath ) ) } \n` +
315
+ `Cannot load Cordova config. \n` +
306
316
`${ msg } `
307
317
) ;
308
318
}
0 commit comments