UNPKG

adcutil

Version:

Utilities tools for Askia Design Control

1,199 lines (1,038 loc) 39.5 kB
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>The source code</title> <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" /> <script type="text/javascript" src="../resources/prettify/prettify.js"></script> <style type="text/css"> .highlight { display: block; background-color: #ddd; } </style> <script type="text/javascript"> function highlight() { document.getElementById(location.hash.replace(/#/, "")).className = "highlight"; } </script> </head> <body onload="prettyPrint(); highlight();"> <pre class="prettyprint lang-js">/* ASP Classic asp ASP.NET aspx axd asx asmx ashx axd ascx CSS css hss sass less ccss pcss Coldfusion cfm Erlang yaws Flash swf HTML html htm xhtml jhtml Java jsp jspx wss do action JavaScript js Perl pl PHP php php4 php3 phtml Python py Ruby rb rhtml rjs erb XML xml rss atom svg Other (C, perl etc.) cgi dll Executable Extension Format Operating System(s) ACTION Automator Action Mac OS APK Application Android APP Executable Mac OS BAT Batch File Windows BIN Binary Executable Windows, Mac OS, Linux CMD Command Script Windows COM Command File Windows COMMAND Terminal Command Mac OS CPL Control Panel Extension Windows CSH C Shell Script Mac OS, Linux EXE Executable Windows GADGET Windows Gadget Windows INF1 Setup Information File Windows INS Internet Communication Settings Windows INX InstallShield Compiled Script Windows IPA Application iOS ISU InstallShield Uninstaller Script Windows JOB Windows Task Scheduler Job File Windows JSE JScript Encoded File Windows KSH Unix Korn Shell Script Linux LNK File Shortcut Windows MSC Microsoft Common Console Document Windows MSI Windows Installer Package Windows MSP Windows Installer Patch Windows MST Windows Installer Setup Transform File Windows OSX Executable Mac OS OUT Executable Linux PAF Portable Application Installer File Windows PIF Program Information File Windows PRG Executable GEM PS1 Windows PowerShell Cmdlet Windows REG Registry Data File Windows RGS Registry Script Windows RUN Executable Linux SCT Windows Scriptlet Windows SHB Windows Document Shortcut Windows SHS Shell Scrap Object Windows U3P U3 Smart Application Windows VB VBScript File Windows VBE VBScript Encoded Script Windows VBS VBScript File Windows VBSCRIPT Visual Basic Script Windows WORKFLOW Automator Workflow Mac OS WS Windows Script Windows WSF Windows Script Windows Audio File Types and Formats .aif Audio Interchange File Format .iff Interchange File Format .m3u Media Playlist File .m4a MPEG-4 Audio File .mid MIDI File .mp3 MP3 Audio File .mpa MPEG-2 Audio File .ra Real Audio File .wav WAVE Audio File .wma Windows Media Audio File AddType audio/ogg ogg AddType audio/ogg oga AddType audio/webm webma Video Files Types and Formats .3g2 3GPP2 Multimedia File .3gp 3GPP Multimedia File .asf Advanced Systems Format File .asx Microsoft ASF Redirector File .avi Audio Video Interleave File .flv Flash Video File .mov Apple QuickTime Movie .mp4 MPEG-4 Video File .mpg MPEG Video File .rm Real Media File .swf Shockwave Flash Movie .vob DVD Video Object File .wmv Windows Media Video File Markdown md white xml|rss|atom|svg|js|xhtml|htm|html|swf|css|hss|sass|less|ccss|pcss|txt|csv|json| gif|jpeg|jpg|tif|tiff|png|bmp|pdf|ico|cur| aif|iff|m4a|mid|mp3|mpa|ra|wav|wma|ogg|oga|webma| 3g2|3gp|avi|flv|mov|mp4|mpg|rm|wmv|webm md| black cgi|dll|erb|rjs|rhtml|rb|py|phtml|php3|php4|php|pl|action|do|wss|jspx|jsp|jhtml|yaws|cfm|aspx|axd|asx|asmx|ashx|axd|ascx|asp|config| action|apk|app|bat|bin|cmd|com|command|cpl|csh|exe|gadget|inf1|ins|inx|ipa|isu| job|jse|ksh|lnk|msc|msi|msp|mst|ocx|osx|out|paf|pif|prg|ps1|reg|rgs|run|sct|shb|shs|u3p| vb|vbe|vbs|vbscript|workflow|ws|wsf|cs|cpp| zip|rar|sql|ini|dmg|iso|vcd|class|java|htaccess */ var fs = require(&#39;fs&#39;); var pathHelper = require(&#39;path&#39;); var xml2js = require(&#39;xml2js&#39;); var util = require(&#39;util&#39;); var common = require(&#39;../common/common.js&#39;); var errMsg = common.messages.error; var warnMsg = common.messages.warning; var successMsg = common.messages.success; var msg = common.messages.message; // Test the file extension var fileExt = { blacklist : /\.(cgi|dll|erb|rjs|rhtml|rb|py|phtml|php3|php4|php|pl|action|do|wss|jspx|jsp|jhtml|yaws|cfm|aspx|axd|asx|asmx|ashx|axd|ascx|asp|config|action|apk|app|bat|bin|cmd|com|command|cpl|csh|exe|gadget|inf1|ins|inx|ipa|isu|job|jse|ksh|lnk|msc|msi|msp|mst|ocx|osx|out|paf|pif|prg|ps1|reg|rgs|run|sct|shb|shs|u3p|vb|vbe|vbs|vbscript|workflow|ws|wsf|cs|cpp|zip|rar|sql|ini|dmg|iso|vcd|class|java|htaccess)$/gi, whitelist : /\.(xml|rss|atom|svg|js|xhtml|htm|html|swf|css|hss|sass|less|ccss|pcss|txt|csv|json|gif|jpeg|jpg|tif|tiff|png|bmp|pdf|ico|cur|aif|iff|m4a|mid|mp3|mpa|ra|wav|wma|ogg|oga|webma|3g2|3gp|avi|flv|mov|mp4|mpg|rm|wmv|ogv|webm|md)$/gi }; // Hash with all content type var contentType = { &#39;text&#39; : &#39;text&#39;, &#39;html&#39; : &#39;text&#39;, &#39;javascript&#39;: &#39;text&#39;, &#39;css&#39; : &#39;text&#39;, &#39;binary&#39; : &#39;binary&#39;, &#39;image&#39; : &#39;binary&#39;, &#39;video&#39; : &#39;binary&#39;, &#39;audio&#39; : &#39;binary&#39;, &#39;flash&#39; : &#39;binary&#39; }; /* * Hash with the rule of the &lt;attribute&gt; node in the &lt;content&gt; * Indicates if the attribute is overridable or not * true for not-overridable */ var contentSealAttr = { &#39;javascript&#39; : { &#39;src&#39; : true, &#39;type&#39; : false }, &#39;css&#39; : { &#39;href&#39; : true, &#39;rel&#39; : false }, &#39;image&#39; : { &#39;src&#39; : true, &#39;alt&#39; : false }, &#39;video&#39; : { &#39;src&#39; : true }, &#39;audio&#39; : { &#39;src&#39; : true } }; // Hash with the rule of the constraint attribute node. var constraintAttributeRules = { questions : [&#39;chapter&#39;, &#39;single&#39;, &#39;multiple&#39;, &#39;open&#39;, &#39;numeric&#39;, &#39;date&#39;, &#39;requireParentLoop&#39;], responses : [&#39;min&#39;, &#39;max&#39;], controls : [&#39;label&#39;, &#39;textbox&#39;, &#39;checkbox&#39;, &#39;listbox&#39;, &#39;radiobutton&#39;, &#39;responseblock&#39;] }; /* * Build a new error messag * @param {String} message Error message * @return {Error} New error */ function newError(message) { return new Error(util.format.apply(null, arguments)); } <span id='ADC-Validator'>/** </span> * Validate the ADC files structure, configuration and logical * * @class ADC.Validator * @private */ function Validator(adcDirPath) { <span id='ADC-Validator-property-rootdir'> /** </span> * Root dir of the current ADCUtil */ this.rootdir = pathHelper.resolve(__dirname, &quot;../../&quot;); <span id='ADC-Validator-property-adcName'> /** </span> * Name of the ADC * @type {string} */ this.adcName = &#39;&#39;; <span id='ADC-Validator-property-adcDirectoryPath'> /** </span> * Path to the ADC directory * @type {string} */ this.adcDirectoryPath = adcDirPath ? pathHelper.normalize(adcDirPath) : process.cwd(); <span id='ADC-Validator-property-validators'> /** </span> * Validators * * @type {{current: number, sequence: string[]}} */ this.validators = { current : -1, sequence : [ &#39;validatePathArg&#39;, &#39;validateADCDirectoryStructure&#39;, &#39;validateFileExtensions&#39;, &#39;validateXMLAgainstXSD&#39;, &#39;initConfigXMLDoc&#39;, &#39;validateADCInfo&#39;, &#39;validateADCInfoConstraints&#39;, &#39;validateADCOutputs&#39;, &#39;validateADCProperties&#39;, &#39;runAutoTests&#39;, &#39;runADCUnitTests&#39; ] }; <span id='ADC-Validator-property-report'> /** </span> * Report of the validation * * @type {{startTime: null, endTime: null, runs: number, total: number, success: number, warnings: number, errors: number}} */ this.report = { startTime : null, endTime : null, runs : 0, total : 0, success : 0, warnings : 0, errors : 0 }; <span id='ADC-Validator-property-dirResources'> /** </span> * Map all files in the resources directory * * @type {{isExist: boolean, dynamic: {isExist: boolean}, statics: {isExist: boolean}, share: {isExist: boolean}}} */ this.dirResources = { isExist : false, dynamic : { isExist : false }, statics : { isExist : false }, share : { isExist : false } }; <span id='ADC-Validator-property-configXmlDoc'> /** </span> * Config xml document in json format */ this.configXmlDoc = null; <span id='ADC-Validator-property-logger'> /** </span> * Logger to override with an object * @type {{writeMessage : function, writeSuccess : function, writeWarning: function, writeError : function}} */ this.logger = null; } <span id='ADC-Validator-method-constructor'>/** </span> * Create a new instance of ADC validator * * @constructor * @param {String} adcDirPath Path of the ADC directory */ Validator.prototype.constructor = Validator; <span id='ADC-Validator-method-validate'>/** </span> * Validate the current ADC instance * * @param {Object} [options] Options of validation * @param {Boolean} [options.test=true] Run unit tests * @param {Boolean} [options.autoTest=true] Run auto unit tests * @param {Boolean} [options.xml=true] Validate the config.xml file * @param {InteractiveADXShell} [options.adxShell] Interactive ADXShell process * @param {Object} [options.logger] Logger * @param {Function} [options.writeMessage] Function where regular messages will be print * @param {Function} [options.writeSuccess] Function where success messages will be print * @param {Function} [options.writeWarning] Function where warning messages will be print * @param {Function} [options.writeError] Function where error messages will be print * @param {Function} [callback] Callback function * @param {Error} [callback.err] Error * @param {Object} [callback.report] Validation report */ Validator.prototype.validate = function validate(options, callback) { // Start timer this.report.startTime = new Date().getTime(); // Swap optional options arguments if (typeof options === &#39;function&#39;) { callback = options; options = null; } if (!options) { options = { test : true, autoTest : true, xml : true } } // Register the end callback for future usage this.validationCallback = callback; this._adxShell = (options &amp;&amp; options.adxShell) || null; // Validate according to the options if (options) { // Set the logger if (options.logger) { this.logger = options.logger; } // --no-autoTest if (options.autoTest === false) { // Check bool value not falsy this.removeOnSequence([&#39;runAutoTests&#39;]); } // --no-test if (options.test === false) { // Check bool value not falsy this.removeOnSequence([&#39;runADCUnitTests&#39;]); } // --no-xml if (options.xml === false) { // Check bool value not falsy this.removeOnSequence([ &#39;validateXMLAgainstXSD&#39;, &#39;initConfigXMLDoc&#39;, &#39;validateADCInfo&#39;, &#39;validateADCInfoConstraints&#39;, &#39;validateADCOutputs&#39;, &#39;validateADCProperties&#39; ]); } } this.report.total = this.validators.sequence.length; this.resume(null); }; <span id='ADC-Validator-method-removeOnSequence'>/** </span> * Remove the specified validators on the validators sequence * * @param {Array} validators Validators to remove */ Validator.prototype.removeOnSequence = function removeOnSequence(validators) { var sequence = this.validators.sequence, index; validators.forEach(function (value) { index = sequence.indexOf(value); if (index !== -1) { sequence.splice(index, 1); } }); }; <span id='ADC-Validator-method-done'>/** </span> * Summarize the validation * * @param {Error} [err] Last error */ Validator.prototype.done = function done(err) { this.report.endTime = new Date().getTime(); var executionTime = this.report.endTime - this.report.startTime, report = this.report, message; if (err) { this.writeError(err.message); } // Write the summary this.writeMessage(msg.validationFinishedIn, executionTime); message = util.format(msg.validationReport, report.runs, report.total, report.success, report.warnings, report.errors, report.total - report.runs); if (report.errors) { this.writeError(message); } else if (report.warnings) { this.writeWarning(message); } else { this.writeSuccess(message); } if (typeof this.validationCallback === &#39;function&#39;) { this.validationCallback(err, this.report); } }; <span id='ADC-Validator-method-resume'>/** </span> * Execute the next validation * * @param {Error|void} err Error which occured during the previous validation */ Validator.prototype.resume = function resume(err) { if (err) { // Mark the error this.report.errors++; this.done(err); return; } var validators = this.validators; // Mark the success if (validators.current !== -1 &amp;&amp; this[validators.sequence[validators.current]]) { this.report.success++; } validators.current++; if (validators.current &gt;= validators.sequence.length) { this.done(err); return; } // Search the next validators (recursive call) var validatorName = validators.sequence[validators.current]; if (!this[validatorName]) { this.resume(null); return; } // Execute the find validator // Mark the runs this.report.runs++; this[validatorName](); }; <span id='ADC-Validator-method-writeError'>/** </span> * Write an error output in the console or in the logger * @param {String} text Text to write in the console */ Validator.prototype.writeError = function writeError(text) { if (this.logger &amp;&amp; typeof this.logger.writeError === &#39;function&#39;) { this.logger.writeError.apply(this.logger, arguments); } else { common.writeError.apply(common, arguments); } }; <span id='ADC-Validator-method-writeWarning'>/** </span> * Write a warning output in the console or in the logger * @param {String} text Text to write in the console */ Validator.prototype.writeWarning = function writeWarning(text) { if (this.logger &amp;&amp; typeof this.logger.writeWarning === &#39;function&#39;) { this.logger.writeWarning.apply(this.logger, arguments); } else { common.writeWarning.apply(common, arguments); } }; <span id='ADC-Validator-method-writeSuccess'>/** </span> * Write a success output in the console or in the logger * @param {String} text Text to write in the console */ Validator.prototype.writeSuccess = function writeSuccess(text) { if (this.logger &amp;&amp; typeof this.logger.writeSuccess === &#39;function&#39;) { this.logger.writeSuccess.apply(this.logger, arguments); } else { common.writeSuccess.apply(common, arguments); } }; <span id='ADC-Validator-method-writeMessage'>/** </span> * Write an arbitrary message in the console or in the logger without specific prefix or in the logger * @param {String} text Text to write in the console */ Validator.prototype.writeMessage = function writeMessage(text) { if (this.logger &amp;&amp; typeof this.logger.writeMessage === &#39;function&#39;) { this.logger.writeMessage.apply(this.logger, arguments); } else { common.writeMessage.apply(common, arguments); } }; <span id='ADC-Validator-method-validatePathArg'>/** </span>* Validate that the `path` argument is correct */ Validator.prototype.validatePathArg = function validatePathArg() { if (!this.adcDirectoryPath) { this.resume(newError(errMsg.missingArgPath)); return; } // Validate the existence of the specify ADC directory var self = this; common.dirExists(self.adcDirectoryPath, function verifyADCDirectory(err, exists) { var er; if (!exists) { er = newError(errMsg.noSuchFileOrDirectory, pathHelper.normalize(self.adcDirectoryPath)); } else { self.writeSuccess(successMsg.pathValidate); } self.resume(er); }); }; <span id='ADC-Validator-method-validateADCDirectoryStructure'>/** </span> * Validate the structure of the ADC directory */ Validator.prototype.validateADCDirectoryStructure = function validateADCDirectoryStructure() { // Verify if the config.xml exists var self = this; fs.exists(pathHelper.join(self.adcDirectoryPath, common.CONFIG_FILE_NAME), function verifyConfigFileExist(exists) { var resourcesPath = pathHelper.join(self.adcDirectoryPath, common.RESOURCES_DIR_NAME), dirResources = self.dirResources; // Check the resources directory function loadResources() { common.dirExists(resourcesPath, function initResourcesFileMap(er, find) { if (!find) { self.resume(null); return; } dirResources.isExist = true; loadDynamic(); }); } // Check the dynamic directory function loadDynamic() { common.dirExists(pathHelper.join(resourcesPath, common.DYNAMIC_DIR_NAME), function initDynamicFileMap(er, find) { var dirDynamic = dirResources.dynamic; dirDynamic.isExist = find; if (find) { try { var files = fs.readdirSync(pathHelper.join(resourcesPath, common.DYNAMIC_DIR_NAME)); files.forEach(function (file) { if (common.isIgnoreFile(file)) { return; } dirDynamic[file.toLocaleLowerCase()] = file; }) } catch (ex) { // Do nothing } } loadStatic(); }); } // Check the static directory function loadStatic(){ common.dirExists(pathHelper.join(resourcesPath, common.STATIC_DIR_NAME), function initStaticFileMap(er, find) { var dirStatic = dirResources.statics; dirStatic.isExist = find; if (find) { try { var files = fs.readdirSync(pathHelper.join(resourcesPath, common.STATIC_DIR_NAME)); files.forEach(function (file) { if (common.isIgnoreFile(file)) { return; } dirStatic[file.toLocaleLowerCase()] = file; }) } catch (ex) { // Do nothing } } loadShare(); }); } // Check the share directory and resume the validation function loadShare() { common.dirExists(pathHelper.join(resourcesPath, common.SHARE_DIR_NAME), function initShareFileMap(er, find) { var dirShare = dirResources.share; dirShare.isExist = find; if (find) { try { var files = fs.readdirSync(pathHelper.join(resourcesPath, common.SHARE_DIR_NAME)); files.forEach(function (file) { if (common.isIgnoreFile(file)) { return; } dirShare[file.toLocaleLowerCase()] = file; }) } catch (ex) { // Do nothing } } self.resume(null); }); } if (!exists) { self.resume(newError(errMsg.noConfigFile)); } else { self.writeSuccess(successMsg.directoryStructureValidate); loadResources(); } }); }; <span id='ADC-Validator-method-validateFileExtensions'>/** </span> * Validate all file extension against the while list and the black list */ Validator.prototype.validateFileExtensions = function validateFileExtensions() { var dirResources = this.dirResources, dir = [dirResources.dynamic, dirResources.statics, dirResources.share], current, i, l, key, match; if (!dirResources.isExist) { this.resume(null); } for (i = 0, l = dir.length; i &lt; l; i++) { current = dir[i]; if (current.isExist) { for (key in current) { if (current.hasOwnProperty(key) &amp;&amp; key !== &#39;isExist&#39;) { // Test against the black list match = key.toString().match(fileExt.blacklist); if (match) { this.resume(newError(errMsg.fileExtensionForbidden, match[0])); return; } // Test against the white list match = key.toString().match(fileExt.whitelist); if (!match) { this.report.warnings++; this.writeWarning(warnMsg.untrustExtension, key); } } } } } this.writeSuccess(successMsg.fileExtensionValidate); this.resume(null); }; <span id='ADC-Validator-method-validateXMLAgainstXSD'>/** </span> * Validate the config.xml file of the ADC against the XSD schema */ Validator.prototype.validateXMLAgainstXSD = function validateXMLAgainstXSD() { var exec = require(&#39;child_process&#39;).exec, xmlLintPath = pathHelper.join(this.rootdir, common.XML_LINT_PATH), xmlSchemaPath = pathHelper.join(this.rootdir, common.SCHEMA_PATH, common.SCHEMA_CONFIG), xmlPath = pathHelper.join(this.adcDirectoryPath, common.CONFIG_FILE_NAME), self = this, commandLine = &#39;&quot;&#39; + xmlLintPath + &#39;&quot; --noout --schema &quot;&#39; + xmlSchemaPath + &#39;&quot; &quot;&#39; + xmlPath + &#39;&quot;&#39;; exec(commandLine, function callback(err) { if (!err) { self.writeSuccess(successMsg.xsdValidate); } self.resume(err); }); }; <span id='ADC-Validator-method-initConfigXMLDoc'>/** </span> * Initialize the XMLDoc using the config.xml */ Validator.prototype.initConfigXMLDoc = function initConfigXMLDoc() { var self = this; fs.readFile(pathHelper.join(self.adcDirectoryPath, common.CONFIG_FILE_NAME), &#39;utf8&#39;, function readConfigXMLFile(err, data) { if (err) { self.resume(err); return; } // Remove the BOM characters in UTF-8 string data = data.replace(/^\uFEFF/, &#39;&#39;); xml2js.parseString(data, function parseXML(err, result) { self.configXmlDoc = result; if (!err) { self.writeSuccess(successMsg.xmlInitialize); } self.resume(err); }); }); }; <span id='ADC-Validator-method-validateADCInfo'>/** </span> * Validate the info of the ADC config file */ Validator.prototype.validateADCInfo = function validateADCInfo() { var infosEl = this.configXmlDoc.control.info &amp;&amp; this.configXmlDoc.control.info[0], nameEl = infosEl &amp;&amp; infosEl.name &amp;&amp; infosEl.name[0]; if (!infosEl) { this.resume(newError(errMsg.missingInfoNode)); return; } if (!nameEl) { this.resume(newError(errMsg.missingOrEmptyNameNode)); return; } this.adcName = nameEl; this.writeSuccess(successMsg.xmlInfoValidate); this.resume(null); }; <span id='ADC-Validator-method-validateADCInfoConstraints'>/** </span> * Validate the info/constraints of the ADC config file */ Validator.prototype.validateADCInfoConstraints = function validateADCInfoConstraints() { var constraintsEl = this.configXmlDoc.control.info[0].constraints[0], constraints = constraintsEl.constraint || [], constraintsOn = { questions : 0, responses : 0, controls : 0 }, attr, i, l, key, hasRule = false; for (i = 0, l = constraints.length; i &lt; l; i++) { hasRule = false; attr = constraints[i].$ || {}; if (!attr.on) { continue; } // Validate the duplicate constraints constraintsOn[attr.on]++; if (constraintsOn[attr.on] &gt; 1) { this.resume(newError(errMsg.duplicateConstraints, attr.on)); return; } // Validate the attribute logic for (key in attr) { if (attr.hasOwnProperty(key) &amp;&amp; key !== &#39;on&#39;) { if (constraintAttributeRules[attr.on].indexOf(key) === -1) { this.resume(newError(errMsg.invalidConstraintAttribute, attr.on, key)); return; } if (key !== &#39;min&#39; &amp;&amp; key !== &#39;max&#39;) { if (attr[key] == &#39;1&#39; || attr[key] == &#39;true&#39;) { hasRule = true; } } else { hasRule = true; } } } // No rule specified if (!hasRule) { this.resume(newError(errMsg.noRuleOnConstraint, attr.on)); return; } } if (!constraintsOn.questions) { this.resume(newError(errMsg.requireConstraintOn, &#39;questions&#39;)); return; } if (!constraintsOn.controls) { this.resume(newError(errMsg.requireConstraintOn, &#39;controls&#39;)); return; } this.writeSuccess(successMsg.xmlInfoConstraintsValidate); this.resume(null); }; <span id='ADC-Validator-method-validateADCOutputs'>/** </span> * Validate the outputs of the ADC config file */ Validator.prototype.validateADCOutputs = function validateADCOutputs() { var outputsEl = this.configXmlDoc.control.outputs[0], outputs = outputsEl.output, conditions = {}, outputsEmptyCondition = [], htmlFallBackCount = 0, lastOutput, defaultGeneration, i, l, output, id, condition, err; for (i = 0, l = outputs.length; i &lt; l; i++) { output = outputs[i]; id = output.$.id; condition = output.condition &amp;&amp; output.condition[0]; defaultGeneration = output.$.defaultGeneration || false; if (!condition) { outputsEmptyCondition.push(id); } if (condition &amp;&amp; conditions[condition]) { this.report.warnings++; this.writeWarning(warnMsg.duplicateOutputCondition, conditions[condition], id); } conditions[condition] = id; lastOutput = { id : id, defaultGeneration : defaultGeneration, contents : output.content || [], condition : condition, dynamicContentCount : 0, javascriptContentCount : 0, flashContentCount : 0 }; err = this.validateADCContents(lastOutput); if (defaultGeneration || !lastOutput.javascriptContentCount) { htmlFallBackCount++; } if (err) { this.resume(err); return; } } if (outputsEmptyCondition.length &gt; 1) { err = newError(errMsg.tooManyEmptyCondition, outputsEmptyCondition.join(&quot;, &quot;)); } if (!htmlFallBackCount) { this.report.warnings++; this.writeWarning(warnMsg.noHTMLFallBack); } if (!err) { this.writeSuccess(successMsg.xmlOutputsValidate); } this.resume(err); }; <span id='ADC-Validator-method-validateADCContents'>/** </span> * Validate the contents of an ADC output * * @param {Object} output Helper output object * @return {Error|void} Return the error or null when no error. */ Validator.prototype.validateADCContents = function validateADCContents(output) { var contents = output.contents, i, l, err = null, condition = output.condition || &quot;&quot;; if (contents.length &amp;&amp; !this.dirResources.isExist) { return newError(errMsg.noResourcesDirectory); } for (i = 0, l = contents.length; i &lt; l; i++) { err = this.validateADCContent(output, contents[i]); if (err) { return err; } } if (!output.defaultGeneration &amp;&amp; !output.dynamicContentCount) { return newError(errMsg.dynamicFileRequire, output.id); } if (!output.defaultGeneration &amp;&amp; output.javascriptContentCount &amp;&amp; !/browser\.support\(&quot;javascript&quot;\)/gi.test(condition)) { this.report.warnings++; this.writeWarning(warnMsg.javascriptUseWithoutBrowserCheck, output.id); } if (!output.defaultGeneration &amp;&amp; output.flashContentCount &amp;&amp; !/browser\.support\(&quot;flash&quot;\)/gi.test(condition)) { this.report.warnings++; this.writeWarning(warnMsg.flashUseWithoutBrowserCheck, output.id); } return err; }; <span id='ADC-Validator-method-validateADCContent'>/** </span> * Validate the content of an ADC output * * @param {Object} output Helper output object * @param {Object} content Content node * @return {Error|void} Return the error or null when no error. */ Validator.prototype.validateADCContent = function validateADCContent(output, content) { var atts = content.$, type = atts.type, position = atts.position, mode = atts.mode, key = (mode !== &#39;static&#39;) ? mode : &#39;statics&#39;, fileName = atts.fileName, yieldNode = content[&#39;yield&#39;] || [], dirResources = this.dirResources; // Missing directory if (!dirResources[key].isExist) { return newError(errMsg.cannotFindDirectory, mode); } // Missing file if (!dirResources[key][fileName.toLocaleLowerCase()]) { return newError(errMsg.cannotFindFileInDirectory, output.id, fileName, mode); } // A binary file could not be dynamic if (mode === &#39;dynamic&#39; &amp;&amp; contentType[type] === &#39;binary&#39;) { return newError(errMsg.typeCouldNotBeDynamic, output.id, type, fileName); } // A binary file require a &#39;yield&#39; node or &#39;position=none&#39; if (type === &#39;binary&#39; &amp;&amp; position !== &#39;none&#39; &amp;&amp; !yieldNode.length) { return newError(errMsg.yieldRequireForBinary, output.id, fileName); } // Increment the information about the dynamic content if (position !== &#39;none&#39; &amp;&amp; mode === &#39;dynamic&#39; &amp;&amp; (type === &#39;javascript&#39; || type === &#39;html&#39;)) { output.dynamicContentCount++; } // Increment the information about the javascript content if (type === &#39;javascript&#39;) { output.javascriptContentCount++; } // Increment the information about the flash content if (type === &#39;flash&#39;) { output.flashContentCount++; } // Validate attribute return this.validateADCContentAttribute(output, content); }; <span id='ADC-Validator-method-validateADCContentAttribute'>/** </span> * Validate the attribute tag of the content node * * @param {Object} output Helper output object * @param {Object} content Content node * @return {Error|void} Return error or null when no error */ Validator.prototype.validateADCContentAttribute = function validateADCContentAttribute(output, content) { if (!content.attribute || !content.attribute.length) { return null; } var atts = content.$, type = atts.type, mode = atts.mode, fileName = atts.fileName, attributes = content.attribute, attribute, attName, attMap = {}, i, l; // Attribute nodes are ignored for the following type if (/(text|binary|html|flash)/.test(type)) { this.report.warnings++; this.writeWarning(warnMsg.attributeNodeWillBeIgnored, output.id, type, fileName); } // Attribute nodes are ignored for dynamic mode if (mode === &#39;dynamic&#39;) { this.report.warnings++; this.writeWarning(warnMsg.attributeNodeAndDynamicContent, output.id, fileName); } // Attribute nodes are ignored with yield if (content[&#39;yield&#39;] &amp;&amp; content[&#39;yield&#39;].length) { this.report.warnings++; this.writeWarning(warnMsg.attributeNodeAndYieldNode, output.id, fileName); } for (i = 0, l = attributes.length; i &lt; l; i++) { attribute = attributes[i]; attName = (attribute.$ &amp;&amp; attribute.$.name &amp;&amp; attribute.$.name.toLocaleLowerCase()) || &#39;&#39;; if (contentSealAttr[type] &amp;&amp; contentSealAttr[type][attName]) { return newError(errMsg.attributeNotOverridable, output.id, attName, fileName); } if (attMap[attName]) { return newError(errMsg.duplicateAttributeNode, output.id, attName, fileName); } if (attName) { attMap[attName] = attName; } } return null; }; <span id='ADC-Validator-method-validateADCProperties'>/** </span> * Validate the ADC properties node */ Validator.prototype.validateADCProperties = function validateADCProperties() { var propertiesEl = (this.configXmlDoc.control.properties &amp;&amp; this.configXmlDoc.control.properties[0]) || {}, categories = propertiesEl.category || [], properties = propertiesEl.property || []; if (!properties.length &amp;&amp; !categories.length) { this.report.warnings++; this.writeWarning(warnMsg.noProperties); } this.writeSuccess(successMsg.xmlPropertiesValidate); this.resume(null); }; <span id='ADC-Validator-method-runTests'>/** </span> * Run the ADC Unit tests process with specify arguments * @param {Array} args * @param {String} message */ Validator.prototype.runTests = function runTests(args, message) { var self = this; // Validate the existence of the specify unit test directory common.dirExists(pathHelper.join(self.adcDirectoryPath, common.UNIT_TEST_DIR_PATH), function verifyUnitTestDirectory(err, exists) { if (!exists) { self.resume(null); return ; } function execCallback(err, data, stderr) { if (stderr) { err = new Error(stderr); } self.writeMessage(message); if (err) { self.report.warnings++; self.writeWarning(&quot;\r\n&quot; + err.message); if (data) { self.writeMessage(data); } } else { self.writeMessage(data); self.writeSuccess(successMsg.adcUnitSucceed); } self.resume(null); } if (!self._adxShell) { var execFile = require(&#39;child_process&#39;).execFile; execFile(&#39;.\\&#39; + common.ADC_UNIT_PROCESS_NAME, args, { cwd : pathHelper.join(self.rootdir, common.ADC_UNIT_DIR_PATH), env : process.env }, execCallback); } else { var escapedArgs = []; for (var i = 0, l = args.length; i &lt; l; i += 1) { escapedArgs.push(&#39;&quot;&#39; + args[i] + &#39;&quot;&#39;); } self._adxShell.exec(&#39;test &#39; + escapedArgs.join(&#39; &#39;), execCallback); } }); }; <span id='ADC-Validator-method-runAutoTests'>/** </span> * Run the ADC unit tests auto-generated */ Validator.prototype.runAutoTests = function runAutoTests() { this.runTests([&#39;--auto&#39;, this.adcDirectoryPath], msg.runningAutoUnit); }; <span id='ADC-Validator-method-runADCUnitTests'>/** </span> * Run the ADC unit tests */ Validator.prototype.runADCUnitTests = function runADCUnitTests() { this.runTests([this.adcDirectoryPath], msg.runningADCUnit); }; // Export the Validator object exports.Validator = Validator; /* * Validate an ADC (CLI) * * @param {Command} program Commander object which hold the arguments pass to the program * @param {String} path Path to the ADC directory * @param {Function} callback Callback function to run at the end it take a single Error argument */ exports.validate = function validate(program, path, callback) { var validator = new Validator(path); validator.validate(program, callback); }; </pre> </body> </html>