1
+ ( function ( exports , semver ) {
2
+
3
+ exports . blacklist = [ ] ;
4
+ exports . suites = [ ] ;
5
+
6
+ function isObject ( obj ) {
7
+ return ( { } ) . toString . call ( obj ) === "[object Object]" ;
8
+ }
9
+
10
+ function isUrl ( /*str*/ ) {
11
+ // TODO: URL validation
12
+ return true ;
13
+ }
14
+
15
+ function isEmail ( str ) {
16
+ return ( / ^ [ a - z A - Z 0 - 9 . ! # $ % & ' * + \/ = ? \^ _ ` { | } ~ \- ] + @ [ a - z A - Z 0 - 9 \- ] + (?: \. [ a - z A - Z 0 - 9 \- ] + ) * $ / ) . test ( str ) ;
17
+ }
18
+
19
+ exports . validate = function ( manifest , version , prefix , filename ) {
20
+ var errors = [ ] ;
21
+
22
+ /** required fields **/
23
+
24
+ if ( ! manifest . name ) {
25
+ errors . push ( "Missing required field: name." ) ;
26
+ } else if ( typeof manifest . name !== "string" ) {
27
+ errors . push ( "Invalid data type for name; must be a string." ) ;
28
+ } else if ( ! ( / ^ [ a - z A - Z 0 - 9 _ \. \- ] + $ / ) . test ( manifest . name ) ) {
29
+ errors . push ( "Name contains invalid characters." ) ;
30
+ } else if ( exports . blacklist . indexOf ( manifest . name ) !== - 1 ) {
31
+ errors . push ( "Name must not be '" + manifest . name + "'." ) ;
32
+ } else {
33
+ if ( prefix ) {
34
+ if ( manifest . name . indexOf ( prefix ) !== 0 ) {
35
+ errors . push ( "Name must start with '" + prefix + "'." ) ;
36
+ }
37
+ } else {
38
+ Object . keys ( exports . suites ) . forEach ( function ( repoId ) {
39
+ var prefix = exports . suites [ repoId ] ;
40
+ if ( manifest . name . indexOf ( prefix ) === 0 &&
41
+ ! ( / \. / ) . test ( manifest . name . substr ( prefix . length ) ) ) {
42
+ errors . push ( "Name must not start with '" + prefix + "'." ) ;
43
+ }
44
+ } ) ;
45
+ }
46
+
47
+ if ( filename && filename . substr ( 0 , filename . length - 12 ) !== manifest . name ) {
48
+ errors . push ( "Name must match manifest file name." ) ;
49
+ }
50
+ }
51
+
52
+ if ( ! manifest . version ) {
53
+ errors . push ( "Missing required field: version." ) ;
54
+ } else if ( typeof manifest . version !== "string" ) {
55
+ errors . push ( "Invalid data type for version; must be a string." ) ;
56
+ } else if ( manifest . version !== semver . clean ( manifest . version ) ) {
57
+ errors . push ( "Manifest version (" + manifest . version + ") is invalid." ) ;
58
+ // version may not be provided when run as a standalone validator
59
+ } else if ( version && ( manifest . version !== semver . clean ( version ) ) ) {
60
+ errors . push ( "Manifest version (" + manifest . version + ") does not match tag (" + version + ")." ) ;
61
+ }
62
+
63
+ if ( ! manifest . title ) {
64
+ errors . push ( "Missing required field: title." ) ;
65
+ } else if ( typeof manifest . title !== "string" ) {
66
+ errors . push ( "Invalid data type for title; must be a string." ) ;
67
+ }
68
+
69
+ if ( ! manifest . author ) {
70
+ errors . push ( "Missing required field: author." ) ;
71
+ } else if ( ! isObject ( manifest . author ) ) {
72
+ errors . push ( "Invalid data type for author; must be an object." ) ;
73
+ } else if ( ! manifest . author . name ) {
74
+ errors . push ( "Missing required field: author.name." ) ;
75
+ } else {
76
+ if ( typeof manifest . author . name !== "string" ) {
77
+ errors . push ( "Invalid data type for author.name; must be a string." ) ;
78
+ }
79
+
80
+ if ( "email" in manifest . author ) {
81
+ if ( typeof manifest . author . email !== "string" ) {
82
+ errors . push ( "Invalid data type for author.email; must be a string." ) ;
83
+ } else if ( ! isEmail ( manifest . author . email ) ) {
84
+ errors . push ( "Invalid value for author.email." ) ;
85
+ }
86
+ }
87
+
88
+ if ( "url" in manifest . author ) {
89
+ if ( typeof manifest . author . url !== "string" ) {
90
+ errors . push ( "Invalid data type for author.url; must be a string." ) ;
91
+ } else if ( ! isUrl ( manifest . author . url ) ) {
92
+ errors . push ( "Invalid value for author.url." ) ;
93
+ }
94
+ }
95
+ }
96
+
97
+ if ( ! manifest . licenses ) {
98
+ errors . push ( "Missing required field: licenses." ) ;
99
+ } else if ( ! Array . isArray ( manifest . licenses ) ) {
100
+ errors . push ( "Invalid data type for licenses; must be an array." ) ;
101
+ } else if ( ! manifest . licenses . length ) {
102
+ errors . push ( "There must be at least one license." ) ;
103
+ } else {
104
+ manifest . licenses . forEach ( function ( license , i ) {
105
+ if ( ! license . url ) {
106
+ errors . push ( "Missing required field: licenses[" + i + "].url." ) ;
107
+ } else if ( typeof license . url !== "string" ) {
108
+ errors . push ( "Invalid data type for licenses[" + i + "].url; must be a string." ) ;
109
+ } else if ( ! isUrl ( license . url ) ) {
110
+ errors . push ( "Invalid value for license.url." ) ;
111
+ }
112
+ } ) ;
113
+ }
114
+
115
+ if ( ! manifest . dependencies ) {
116
+ errors . push ( "Missing required field: dependencies." ) ;
117
+ } else if ( ! isObject ( manifest . dependencies ) ) {
118
+ errors . push ( "Invalid data type for dependencies; must be an object." ) ;
119
+ } else {
120
+ if ( ! manifest . dependencies . jquery ) {
121
+ errors . push ( "Missing required dependency: jquery." ) ;
122
+ }
123
+ Object . keys ( manifest . dependencies ) . forEach ( function ( dependency ) {
124
+ if ( typeof manifest . dependencies [ dependency ] !== "string" ) {
125
+ errors . push ( "Invalid data type for dependencies[" + dependency + "];" +
126
+ " must be a string." ) ;
127
+ } else if ( semver . validRange ( manifest . dependencies [ dependency ] ) === null ) {
128
+ errors . push ( "Invalid version range for dependency: " + dependency + "." ) ;
129
+ }
130
+ } ) ;
131
+ }
132
+
133
+ /** optional fields **/
134
+
135
+ if ( "description" in manifest && typeof manifest . description !== "string" ) {
136
+ errors . push ( "Invalid data type for description; must be a string." ) ;
137
+ }
138
+
139
+ if ( "keywords" in manifest ) {
140
+ if ( ! Array . isArray ( manifest . keywords ) ) {
141
+ errors . push ( "Invalid data type for keywords; must be an array." ) ;
142
+ } else {
143
+ manifest . keywords . forEach ( function ( keyword , i ) {
144
+ if ( typeof keyword !== "string" ) {
145
+ errors . push ( "Invalid data type for keywords[" + i + "]; must be a string." ) ;
146
+ } else if ( ! ( / ^ [ a - z A - Z 0 - 9 \. \- ] + $ / ) . test ( keyword ) ) {
147
+ errors . push ( "Invalid characters for keyword: " + keyword + "." ) ;
148
+ }
149
+ } ) ;
150
+ }
151
+ }
152
+
153
+ if ( "homepage" in manifest ) {
154
+ if ( typeof manifest . homepage !== "string" ) {
155
+ errors . push ( "Invalid data type for homepage; must be a string." ) ;
156
+ } else if ( ! isUrl ( manifest . homepage ) ) {
157
+ errors . push ( "Invalid value for homepage." ) ;
158
+ }
159
+ }
160
+
161
+ if ( "docs" in manifest ) {
162
+ if ( typeof manifest . docs !== "string" ) {
163
+ errors . push ( "Invalid data type for docs; must be a string." ) ;
164
+ } else if ( ! isUrl ( manifest . docs ) ) {
165
+ errors . push ( "Invalid value for docs." ) ;
166
+ }
167
+ }
168
+
169
+ if ( "demo" in manifest ) {
170
+ if ( typeof manifest . demo !== "string" ) {
171
+ errors . push ( "Invalid data type for demo; must be a string." ) ;
172
+ } else if ( ! isUrl ( manifest . demo ) ) {
173
+ errors . push ( "Invalid value for demo." ) ;
174
+ }
175
+ }
176
+
177
+ if ( "download" in manifest ) {
178
+ if ( typeof manifest . download !== "string" ) {
179
+ errors . push ( "Invalid data type for download; must be a string." ) ;
180
+ } else if ( ! isUrl ( manifest . download ) ) {
181
+ errors . push ( "Invalid value for download." ) ;
182
+ }
183
+ }
184
+
185
+ if ( "bugs" in manifest ) {
186
+ // check { url: "..." } format
187
+ if ( typeof manifest . bugs === "object" ) {
188
+ if ( typeof manifest . bugs . url !== "string" ) {
189
+ errors . push ( "Invalid data type for bugs.url; must be a string." ) ;
190
+ } else if ( ! isUrl ( manifest . bugs . url ) ) {
191
+ errors . push ( "Invalid value for bugs.url." ) ;
192
+ }
193
+ } else {
194
+ if ( typeof manifest . bugs !== "string" ) {
195
+ errors . push ( "Invalid data type for bugs; must be a string." ) ;
196
+ } else if ( ! isUrl ( manifest . bugs ) ) {
197
+ errors . push ( "Invalid value for bugs." ) ;
198
+ }
199
+ }
200
+ }
201
+
202
+ if ( "maintainers" in manifest ) {
203
+ if ( ! Array . isArray ( manifest . maintainers ) ) {
204
+ errors . push ( "Invalid data type for maintainers; must be an array." ) ;
205
+ } else {
206
+ manifest . maintainers . forEach ( function ( maintainer , i ) {
207
+ if ( ! isObject ( maintainer ) ) {
208
+ errors . push ( "Invalid data type for maintainers[" + i + "]; must be an object." ) ;
209
+ return ;
210
+ }
211
+
212
+ if ( ! ( "name" in maintainer ) ) {
213
+ errors . push ( "Missing required field: maintainers[" + i + "].name." ) ;
214
+ } else if ( typeof maintainer . name !== "string" ) {
215
+ errors . push ( "Invalid data type for maintainers[" + i + "].name; must be a string." ) ;
216
+ }
217
+
218
+ if ( "email" in maintainer ) {
219
+ if ( typeof maintainer . email !== "string" ) {
220
+ errors . push ( "Invalid data type for maintainers[" + i + "].email; must be a string." ) ;
221
+ } else if ( ! isEmail ( maintainer . email ) ) {
222
+ errors . push ( "Invalid value for maintainers[" + i + "].email." ) ;
223
+ }
224
+ }
225
+
226
+ if ( "url" in maintainer ) {
227
+ if ( typeof maintainer . url !== "string" ) {
228
+ errors . push ( "Invalid data type for maintainers[" + i + "].url; must be a string." ) ;
229
+ } else if ( ! isUrl ( maintainer . url ) ) {
230
+ errors . push ( "Invalid value for maintainers[" + i + "].url." ) ;
231
+ }
232
+ }
233
+ } ) ;
234
+ }
235
+ }
236
+
237
+ return errors ;
238
+ } ;
239
+
240
+ } ) (
241
+ typeof exports === "object" ? exports : this . Manifest = { } ,
242
+ this . semver || require ( "semver" )
243
+ ) ;
0 commit comments