@@ -27,25 +27,18 @@ indent: 4, maxerr: 50 */
2727
2828"use strict" ;
2929
30- var unzip = require ( "unzip" ) ,
31- semver = require ( "semver" ) ,
32- path = require ( "path" ) ,
33- http = require ( "http" ) ,
34- request = require ( "request" ) ,
35- os = require ( "os" ) ,
36- fs = require ( "fs-extra" ) ;
30+ var unzip = require ( "unzip" ) ,
31+ semver = require ( "semver" ) ,
32+ path = require ( "path" ) ,
33+ http = require ( "http" ) ,
34+ request = require ( "request" ) ,
35+ os = require ( "os" ) ,
36+ fs = require ( "fs-extra" ) ,
37+ validate = require ( "./package-validator" ) . validate ;
3738
3839
3940var Errors = {
40- NOT_FOUND_ERR : "NOT_FOUND_ERR" , // {0} is path where ZIP file was expected
41- INVALID_ZIP_FILE : "INVALID_ZIP_FILE" , // {0} is path to ZIP file
42- INVALID_PACKAGE_JSON : "INVALID_PACKAGE_JSON" , // {0} is JSON parse error, {1} is path to ZIP file
43- MISSING_PACKAGE_NAME : "MISSING_PACKAGE_NAME" , // {0} is path to ZIP file
44- BAD_PACKAGE_NAME : "BAD_PACKAGE_NAME" , // {0} is the name
45- MISSING_PACKAGE_VERSION : "MISSING_PACKAGE_VERSION" , // {0} is path to ZIP file
46- INVALID_VERSION_NUMBER : "INVALID_VERSION_NUMBER" , // {0} is version string in JSON, {1} is path to ZIP file
4741 API_NOT_COMPATIBLE : "API_NOT_COMPATIBLE" ,
48- MISSING_MAIN : "MISSING_MAIN" , // {0} is path to ZIP file
4942 MISSING_REQUIRED_OPTIONS : "MISSING_REQUIRED_OPTIONS" ,
5043 ALREADY_INSTALLED : "ALREADY_INSTALLED" ,
5144 DOWNLOAD_ID_IN_USE : "DOWNLOAD_ID_IN_USE" ,
@@ -62,162 +55,6 @@ var Errors = {
6255 */
6356var pendingDownloads = { } ;
6457
65- /**
66- * Returns true if the name presented is acceptable as a package name. This enforces the
67- * requirement as presented in the CommonJS spec: http://wiki.commonjs.org/wiki/Packages/1.0
68- *
69- * @param {string } Name to test
70- * @return {boolean } true if the name is valid
71- */
72- function validateName ( name ) {
73- // "This must be a unique, lowercase alpha-numeric name without spaces. It may include "." or "_" or "-" characters."
74- if ( / ^ [ a - z 0 - 9 . _ \- ] + $ / . exec ( name ) ) {
75- return true ;
76- }
77- return false ;
78- }
79-
80- /**
81- * Implements the "validate" command in the "extensions" domain.
82- * Validates the zipped package at path.
83- *
84- * The "err" parameter of the callback is only set if there was an
85- * unexpected error. Otherwise, errors are reported in the result.
86- *
87- * The result object has an "errors" property. It is an array of
88- * arrays of strings. Each array in the array is a set of parameters
89- * that can be passed to StringUtils.format for internationalization.
90- * The array will be empty if there are no errors.
91- *
92- * The result will have a "metadata" property if the metadata was
93- * read successfully from package.json in the zip file.
94- *
95- * @param {string } Absolute path to the package zip file
96- * @param {function } callback (err, result)
97- */
98- function _cmdValidate ( path , callback ) {
99- fs . exists ( path , function ( doesExist ) {
100- if ( ! doesExist ) {
101- callback ( null , {
102- errors : [ [ Errors . NOT_FOUND_ERR , path ] ]
103- } ) ;
104- return ;
105- }
106- var callbackCalled = false ;
107- var metadata ;
108- var foundMainIn = null ;
109- var errors = [ ] ;
110- var commonPrefix = null ;
111-
112- var readStream = fs . createReadStream ( path ) ;
113-
114- readStream
115- . pipe ( unzip . Parse ( ) )
116- . on ( "error" , function ( exception ) {
117- // General error to report for problems reading the file
118- errors . push ( [ Errors . INVALID_ZIP_FILE , path ] ) ;
119- callback ( null , {
120- errors : errors
121- } ) ;
122- callbackCalled = true ;
123- readStream . destroy ( ) ;
124- } )
125- . on ( "entry" , function ( entry ) {
126- // look for the metadata
127- var fileName = entry . path ;
128-
129- var slash = fileName . indexOf ( "/" ) ;
130- if ( slash > - 1 ) {
131- var prefix = fileName . substring ( 0 , slash ) ;
132- if ( commonPrefix === null ) {
133- commonPrefix = prefix ;
134- } else if ( prefix !== commonPrefix ) {
135- commonPrefix = "" ;
136- }
137- if ( commonPrefix ) {
138- fileName = fileName . substring ( commonPrefix . length + 1 ) ;
139- }
140- } else {
141- commonPrefix = "" ;
142- }
143-
144- if ( fileName === "package.json" ) {
145- // This handles an edge case where we found a package.json in a
146- // nested directory that we thought was a commonPrefix but
147- // actually wasn't. We reset as if we never read that first
148- // package.json
149- if ( metadata ) {
150- metadata = undefined ;
151- errors = [ ] ;
152- }
153-
154- var packageJSON = "" ;
155- entry
156- . on ( "data" , function ( data ) {
157- // We're assuming utf8 encoding here, which is pretty safe
158- // Note that I found that .setEncoding on the stream
159- // would fail, so I convert the buffer to a string here.
160- packageJSON += data . toString ( "utf8" ) ;
161- } )
162- . on ( "error" , function ( exception ) {
163- // general exception handler. It is unknown what kinds of
164- // errors we can get here.
165- callback ( exception , null ) ;
166- callbackCalled = true ;
167- readStream . destroy ( ) ;
168- } )
169- . on ( "end" , function ( ) {
170- // attempt to parse the metadata
171- try {
172- metadata = JSON . parse ( packageJSON ) ;
173- } catch ( e ) {
174- errors . push ( [ Errors . INVALID_PACKAGE_JSON , e . toString ( ) , path ] ) ;
175- return ;
176- }
177-
178- // confirm required fields in the metadata
179- if ( ! metadata . name ) {
180- errors . push ( [ Errors . MISSING_PACKAGE_NAME , path ] ) ;
181- } else if ( ! validateName ( metadata . name ) ) {
182- errors . push ( [ Errors . BAD_PACKAGE_NAME , metadata . name ] ) ;
183- }
184- if ( ! metadata . version ) {
185- errors . push ( [ Errors . MISSING_PACKAGE_VERSION , path ] ) ;
186- } else if ( ! semver . valid ( metadata . version ) ) {
187- errors . push ( [ Errors . INVALID_VERSION_NUMBER , metadata . version , path ] ) ;
188- }
189- } ) ;
190- } else if ( fileName === "main.js" ) {
191- foundMainIn = commonPrefix ;
192- }
193- } )
194- . on ( "end" , function ( ) {
195- // Reached the end of the zipfile
196- // Report results
197-
198- // generally, if we hit an exception, we've already called the callback
199- if ( callbackCalled ) {
200- return ;
201- }
202-
203- if ( foundMainIn === null || foundMainIn !== commonPrefix ) {
204- errors . push ( [ Errors . MISSING_MAIN , path ] ) ;
205- }
206-
207- // No errors and no metadata means that we never found the metadata
208- if ( errors . length === 0 && ! metadata ) {
209- metadata = null ;
210- }
211-
212- callback ( null , {
213- errors : errors ,
214- metadata : metadata ,
215- commonPrefix : commonPrefix
216- } ) ;
217- } ) ;
218- } ) ;
219- }
220-
22158
22259/**
22360 * Private function to unzip to the correct directory.
@@ -387,7 +224,7 @@ function _cmdInstall(packagePath, destinationDirectory, options, callback) {
387224 }
388225 } ;
389226
390- _cmdValidate ( packagePath , validateCallback ) ;
227+ validate ( packagePath , { } , validateCallback ) ;
391228}
392229
393230
@@ -511,13 +348,17 @@ function init(domainManager) {
511348 domainManager . registerCommand (
512349 "extensionManager" ,
513350 "validate" ,
514- _cmdValidate ,
351+ validate ,
515352 true ,
516353 "Verifies that the contents of the given ZIP file are a valid Brackets extension package" ,
517354 [ {
518355 name : "path" ,
519356 type : "string" ,
520357 description : "absolute filesystem path of the extension package"
358+ } , {
359+ name : "options" ,
360+ type : "{requirePackageJSON: ?boolean}" ,
361+ description : "options to control the behavior of the validator"
521362 } ] ,
522363 [ {
523364 name : "errors" ,
@@ -609,7 +450,7 @@ function init(domainManager) {
609450}
610451
611452// used in unit tests
612- exports . _cmdValidate = _cmdValidate ;
453+ exports . _cmdValidate = validate ;
613454exports . _cmdInstall = _cmdInstall ;
614455
615456// used to load the domain
0 commit comments