1
1
import * as fs from 'fs' ;
2
2
import * as path from 'path' ;
3
3
4
+ const schemaPath = path . resolve ( process . env . CLI_ROOT , 'lib/config/schema.json' ) ;
5
+ const schema = require ( schemaPath ) ;
4
6
5
7
export const CLI_CONFIG_FILE_NAME = 'angular-cli.json' ;
6
-
7
-
8
- export interface CliConfigJson {
9
- routes ?: { [ name : string ] : any } ,
10
- packages ?: { [ name : string ] : any }
11
- }
8
+ export const ARRAY_METHODS = [ 'push' , 'splice' , 'sort' , 'reverse' , 'pop' , 'shift' ] ;
12
9
13
10
14
11
function _findUp ( name : string , from : string ) {
15
12
let currentDir = from ;
16
- while ( currentDir && currentDir != '/' ) {
13
+ while ( currentDir && currentDir !== path . parse ( currentDir ) . root ) {
17
14
const p = path . join ( currentDir , name ) ;
18
15
if ( fs . existsSync ( p ) ) {
19
16
return p ;
@@ -27,9 +24,22 @@ function _findUp(name: string, from: string) {
27
24
28
25
29
26
export class CliConfig {
30
- constructor ( private _config : CliConfigJson = CliConfig . fromProject ( ) ) { }
27
+ private _config : any ;
28
+
29
+ constructor ( path ?: string ) {
30
+ if ( path ) {
31
+ try {
32
+ fs . accessSync ( path ) ;
33
+ this . _config = require ( path ) ;
34
+ } catch ( e ) {
35
+ throw new Error ( `Config file does not exits.` ) ;
36
+ }
37
+ } else {
38
+ this . _config = this . _fromProject ( ) ;
39
+ }
40
+ }
31
41
32
- save ( path : string = CliConfig . configFilePath ( ) ) {
42
+ save ( path : string = this . _configFilePath ( ) ) {
33
43
if ( ! path ) {
34
44
throw new Error ( 'Could not find config path.' ) ;
35
45
}
@@ -38,18 +48,55 @@ export class CliConfig {
38
48
}
39
49
40
50
set ( jsonPath : string , value : any , force : boolean = false ) : boolean {
51
+ let method : any = null ;
52
+ let splittedPath = jsonPath . split ( '.' ) ;
53
+ if ( ARRAY_METHODS . indexOf ( splittedPath [ splittedPath . length - 1 ] ) != - 1 ) {
54
+ method = splittedPath [ splittedPath . length - 1 ] ;
55
+ splittedPath . splice ( splittedPath . length - 1 , 1 ) ;
56
+ jsonPath = splittedPath . join ( '.' ) ;
57
+ }
58
+
41
59
let { parent, name, remaining } = this . _findParent ( jsonPath ) ;
42
- while ( force && remaining ) {
43
- if ( remaining . indexOf ( '.' ) != - 1 ) {
44
- // Create an empty map.
45
- // TODO: create the object / array based on the Schema of the configuration.
46
- parent [ name ] = { } ;
60
+ let properties : any ;
61
+ let additionalProperties : boolean ;
62
+
63
+ const checkPath = jsonPath . split ( '.' ) . reduce ( ( o , i ) => {
64
+ if ( ! o || ! o . properties ) {
65
+ throw new Error ( `Invalid config path.` ) ;
47
66
}
67
+ properties = o . properties ;
68
+ additionalProperties = o . additionalProperties ;
48
69
70
+ return o . properties [ i ] ;
71
+ } , schema ) ;
72
+ const configPath = jsonPath . split ( '.' ) . reduce ( ( o , i ) => o [ i ] , this . _config ) ;
73
+
74
+ if ( ! properties [ name ] && ! additionalProperties ) {
75
+ throw new Error ( `${ name } is not a known property.` ) ;
49
76
}
50
77
51
- parent [ name ] = value ;
52
- return true ;
78
+ if ( method ) {
79
+ if ( Array . isArray ( configPath ) && checkPath . type === 'array' ) {
80
+ [ ] [ method ] . call ( configPath , value ) ;
81
+ return true ;
82
+ } else {
83
+ throw new Error ( `Trying to use array method on non-array property type.` ) ;
84
+ }
85
+ }
86
+
87
+ if ( typeof checkPath . type === 'string' && isNaN ( value ) ) {
88
+ parent [ name ] = value ;
89
+ return true ;
90
+ }
91
+
92
+ if ( typeof checkPath . type === 'number' && ! isNaN ( value ) ) {
93
+ parent [ name ] = value ;
94
+ return true ;
95
+ }
96
+
97
+ if ( typeof value != checkPath . type ) {
98
+ throw new Error ( `Invalid value type. Trying to set ${ typeof value } to ${ path . type } ` ) ;
99
+ }
53
100
}
54
101
55
102
get ( jsonPath : string ) : any {
@@ -110,16 +157,16 @@ export class CliConfig {
110
157
return { parent, name } ;
111
158
}
112
159
113
- static configFilePath ( projectPath ?: string ) : string {
160
+ private _configFilePath ( projectPath ?: string ) : string {
114
161
// Find the configuration, either where specified, in the angular-cli project
115
162
// (if it's in node_modules) or from the current process.
116
163
return ( projectPath && _findUp ( CLI_CONFIG_FILE_NAME , projectPath ) )
117
164
|| _findUp ( CLI_CONFIG_FILE_NAME , __dirname )
118
165
|| _findUp ( CLI_CONFIG_FILE_NAME , process . cwd ( ) ) ;
119
166
}
120
167
121
- static fromProject ( ) : CliConfigJson {
122
- const configPath = this . configFilePath ( ) ;
168
+ private _fromProject ( ) : any {
169
+ const configPath = this . _configFilePath ( ) ;
123
170
return configPath ? require ( configPath ) : { } ;
124
171
}
125
172
}
0 commit comments