<commit_before>/*
 * grunt-po2json
 * https://github.com/rkitamura/grunt-po2json
 *
 * Copyright (c) 2013 Rocky Kitamura
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  grunt.registerMultiTask('po2json', 'Convert PO to JSON files', function() {
    var options = this.options({
      fuzzy: false,
      stringify: false,
      pretty: false,
      format: 'raw',
      domain: 'messages',
      nodeJs: false,
      es6: false,
      requireJs: false,
      singleFile: false,
      stringOnly: false
    });

    var path = require('path');
    var po2json = require('po2json');

    this.files.forEach(function(line) {
      var dest, extension, out = {};
      line.src.forEach(function(file) {
        var content = po2json.parseFileSync(file, options);
        var filename = path.basename(file, (path.extname(file)));
        if (!options.singleFile)
        {
          extension = (options.nodeJs || options.requireJs ? 'js' : 'json');
          dest = path.join(line.dest, filename + '.' + extension);
          writeObj(content, dest, options);
        }
        else
          out[filename] = content;
      });
      if (options.singleFile)
      {
        if (!path.extname(line.dest))
        {
          extension = (options.nodeJs || options.requireJs ? 'js' : 'json');
          dest = line.dest + '.' + extension;
        }
        else
          dest = line.dest;
        writeObj(out, dest, options);
      }
    });

  });

  var writeObj = function(data, dest, options) {
    if (options.stringOnly)
      data = nullArrayToString(data);
    var contents = JSON.stringify(data);
    if (options.nodeJs) {
      contents = "module.exports = " + contents + ";";
    } else if (options.requireJs) {
      contents =  "define(function() {\n" +
                  "    return " + contents + ";\n" +
                  "});\n";
    } else if (options.es6) {
        contents = "export default " + contents;
    }
    grunt.file.write(dest, contents);
    grunt.log.writeln('File "' + dest + '" created.');
  };

  var nullArrayToString = function(data) {
    var kindOf = grunt.util.kindOf;
    switch (kindOf(data))
    {
      case "array":
        if (data.length == 2 && !data[0] && kindOf(data[1]) == "string")
          return data[1];
        else
          for (var i= 0, max = data.length; i<max; i++)
            data[i] = nullArrayToString(data[i]);
        break;

      case "object":
        for (var name in data)
          if (data.hasOwnProperty(name))
            data[name] = nullArrayToString(data[name]);
        break;
    }
    return data;
  }

};
<commit_msg>es6 support<commit_after>/*
 * grunt-po2json
 * https://github.com/rkitamura/grunt-po2json
 *
 * Copyright (c) 2013 Rocky Kitamura
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  grunt.registerMultiTask('po2json', 'Convert PO to JSON files', function() {
    var options = this.options({
      fuzzy: false,
      stringify: false,
      pretty: false,
      format: 'raw',
      domain: 'messages',
      nodeJs: false,
      es6: false,
      requireJs: false,
      singleFile: false,
      stringOnly: false
    });

    var path = require('path');
    var po2json = require('po2json');

    this.files.forEach(function(line) {
      var dest, extension, out = {};
      line.src.forEach(function(file) {
        var content = po2json.parseFileSync(file, options);
        var filename = path.basename(file, (path.extname(file)));
        if (!options.singleFile)
        {
          extension = (options.nodeJs || options.requireJs || options.es6 ? 'js' : 'json');
          dest = path.join(line.dest, filename + '.' + extension);
          writeObj(content, dest, options);
        }
        else
          out[filename] = content;
      });

      if (options.singleFile)
      {
        if (!path.extname(line.dest))
        {
          extension = (options.nodeJs || options.requireJs || options.es6 ? 'js' : 'json');
          dest = line.dest + '.' + extension;
        }
        else
          dest = line.dest;
        writeObj(out, dest, options);
      }
    });

  });

  var writeObj = function(data, dest, options) {
    if (options.stringOnly)
      data = nullArrayToString(data);
    var contents = JSON.stringify(data);
    if (options.nodeJs) {
      contents = "module.exports = " + contents + ";";
    } else if (options.requireJs) {
      contents =  "define(function() {\n" +
                  "    return " + contents + ";\n" +
                  "});\n";
    } else if (options.es6) {
        contents = "export default " + contents;
    }
    grunt.file.write(dest, contents);
    grunt.log.writeln('File "' + dest + '" created.');
  };

  var nullArrayToString = function(data) {
    var kindOf = grunt.util.kindOf;
    switch (kindOf(data))
    {
      case "array":
        if (data.length == 2 && !data[0] && kindOf(data[1]) == "string")
          return data[1];
        else
          for (var i= 0, max = data.length; i<max; i++)
            data[i] = nullArrayToString(data[i]);
        break;

      case "object":
        for (var name in data)
          if (data.hasOwnProperty(name))
            data[name] = nullArrayToString(data[name]);
        break;
    }
    return data;
  }

};
<|endoftext|>


<commit_before>// Copyright 2016 SAP SE.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http: //www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific
// language governing permissions and limitations under the License.

'use strict';

var path = require('path');
var slash = require('slash');
var uglify = require('uglify-js');
var pd = require('pretty-data').pd;
var maxmin = require('maxmin');

var defaultResourcePatterns = [
	'**/*.js',
	'**/*.fragment.html',
	'**/*.fragment.json',
	'**/*.fragment.xml',
	'**/*.view.html',
	'**/*.view.json',
	'**/*.view.xml',
	'**/*.properties'
];

var copyrightCommentsPattern = /copyright|\(c\)|released under|license|\u00a9/i;
var xmlHtmlPrePattern = /<(?:\w+:)?pre>/;

module.exports = function (grunt) {

	grunt.registerMultiTask('openui5_preload', 'Create OpenUI5 preload files', function() {

		// Merge task-specific and/or target-specific options with these defaults.
		var options = this.options({
			resources: [],
			dest: null,
			compress: true
		});

		var resourceMap = {};

		// normalize string/object to array
		if (typeof options.resources === 'string' || (typeof options.resources === 'object' && !(options.resources instanceof Array))) {
			options.resources = [ options.resources ];
		}

		if (options.resources.length === 0) {
			grunt.fail.warn('"resources" option is not specified!');
			return;
		}

		grunt.verbose.subhead('Collecting resources');

		// process resources array
		options.resources.forEach(function(resource) {
			// transform string shorthand to object
			if (typeof resource === 'string') {
				resource = {
					cwd: resource
				};
			}

			if (typeof resource.prefix !== 'string') {
				resource.prefix = '';
			}

			resource.src = resource.src || defaultResourcePatterns;

			grunt.verbose.writeflags(resource, 'resource');

			grunt.file.expand({
				cwd: resource.cwd,
				dot: true,
				filter: 'isFile'
			}, resource.src).forEach(function(file) {
				var localFile = file;
				if (resource.prefix) {
					localFile = slash(path.join(resource.prefix, file));
				}
				var fullPath = path.join(resource.cwd, file);
				grunt.verbose.write('Collecting ' + localFile + ' (' + fullPath + ')...').ok();
				resourceMap[localFile] = {
					fullPath: fullPath,
					prefix: resource.prefix
				};
			});

		});

		var resourceFiles = Object.keys(resourceMap);

		if (resourceFiles.length === 0) {
			grunt.fail.warn('No files found. Check your "resources" option!');
			return;
		}

		var preloadData = this.data;
		if (!preloadData['components'] && !preloadData['libraries']) {
			grunt.fail.warn('No preload type specified. Please provide "components" and/or "libraries" in task target object!');
			return;
		}

		['components', 'libraries'].forEach(function(preloadType) {

			var preloadOptions = preloadData[preloadType];

			if (!preloadOptions) {
				return;
			}

			var preloadInfo = (preloadType === 'libraries') ? {
				moduleName: 'library-preload',
				ext: '.json',
				indicatorFile: 'library.js',
				processModuleName: function(moduleName) {
					return moduleName.replace(/\//g, '.');
				}
			} : {
				moduleName: 'Component-preload',
				ext: '.js',
				indicatorFile: 'Component.js',
				processContent: function(content) {
					return 'jQuery.sap.registerPreloadedModules(' + content + ');';
				}
			};

			if (preloadOptions === true) {
				preloadOptions = '**';
			}
			if (typeof preloadOptions === 'string') {
				var pattern = preloadOptions;
				preloadOptions = {};
				preloadOptions[pattern] = {};
			}

			var preloadOptionKeys = Object.keys(preloadOptions);

			if (preloadOptionKeys.length === 0) {
				grunt.log.writeflags(preloadOptions, 'preloadOptions');
				grunt.fail.warn('No valid options provided for "' + preloadType + '" preload!');
				return;
			}

			preloadOptionKeys.forEach(function(preloadPattern) {
				var preloadOption = preloadOptions[preloadPattern];
				var preloadFiles = grunt.file.match(preloadPattern + '/' + preloadInfo.indicatorFile, resourceFiles);

				if (preloadFiles.length < 1) {
					grunt.fail.warn('No "' + preloadInfo.indicatorFile + '" found for pattern "' + preloadPattern + '"!');
					return;
				}

				preloadFiles.forEach(function(preloadFile) {
					var preloadDir = path.dirname(preloadFile);
					var preloadModuleName = preloadDir + '/' + preloadInfo.moduleName;

					grunt.verbose.subhead('Creating preload module for ' + preloadFile);

					var preloadObject = {
						version: '2.0',
						name: preloadModuleName,
						modules: {}
					};

					if (typeof preloadInfo.processModuleName === 'function') {
						preloadObject.name = preloadInfo.processModuleName(preloadModuleName);
					} else {
						preloadObject.name = preloadModuleName;
					}

					var preloadPatterns = preloadOption.src ? preloadOption.src : [ preloadDir + '/**' ];
					if (typeof preloadPatterns === "string") {
						preloadPatterns = [ preloadPatterns ];
					}

					// Always exclude the corresponding preload file (Component-preload.js / library-preload.json)
					// Otherwise it might get included every time the build runs if src / dest are the same dir
					preloadPatterns.push('!' + preloadDir + '/' + preloadInfo.moduleName + preloadInfo.ext);

					var preloadFiles = grunt.file.match(preloadPatterns, resourceFiles);
					if (preloadFiles.length === 0) {
						var patternsString = (typeof preloadPatterns === 'string') ? preloadPatterns : preloadPatterns.join('", "');
						grunt.fail.warn('No files found for pattern(s): "' + patternsString + '"!');
						return;
					}

					var iPreloadOriginalSize = 0, iPreloadCompressedSize = 0;

					preloadFiles.forEach(function(preloadFile) {

						var fileName = resourceMap[preloadFile].fullPath;
						var fileContent = grunt.file.read(fileName);
						var fileExtension = path.extname(fileName);

						var iOriginalSize, iCompressedSize;

						if (options.compress) {

							iOriginalSize = fileContent.length;
							iPreloadOriginalSize += iOriginalSize;

							switch (fileExtension) {
							case '.js':
								// Javascript files are processed by Uglify
								fileContent = uglify.minify(fileContent, {
									fromString: true,
									warnings: grunt.option('verbose') === true,
									output: {
										comments: copyrightCommentsPattern
									}
								}).code;
								break;
							case '.json':
								// JSON is parsed and written to string again to remove unwanted white space
								fileContent = JSON.stringify(JSON.parse(fileContent));
								break;
							case '.xml':
								// For XML we use the pretty data

								// Do not minify if XML(View) contains an <*:pre> tag because whitespace of HTML <pre> should be preserved (should only happen rarely)
								if (!xmlHtmlPrePattern.test(fileContent)) {
									fileContent = pd.xmlmin(fileContent, false);
								}

								break;
							}

							iCompressedSize = fileContent.length;
							iPreloadCompressedSize += iCompressedSize;

						}

						if (grunt.option('verbose')) {
							var log = 'Adding ' + preloadFile;
							if (iOriginalSize && iCompressedSize && iOriginalSize !== iCompressedSize) {
								log += ' (' + maxmin({ length: iOriginalSize }, { length: iCompressedSize }) + ')';
							}
							grunt.verbose.writeln(log);
						}

						preloadObject.modules[preloadFile] = fileContent;
					});

					var content = JSON.stringify(preloadObject, null, '\t');
					if (typeof preloadInfo.processContent === 'function') {
						content = preloadInfo.processContent(content);
					}

					var destPath = options.dest;
					var preloadResourceInfo = resourceMap[preloadFile];
					if (preloadModuleName.indexOf(preloadResourceInfo.prefix) === 0) {
						destPath = path.join(destPath, preloadModuleName.substr(preloadResourceInfo.prefix.length));
					} else {
						destPath = path.join(destPath, preloadModuleName);
					}
					destPath += preloadInfo.ext;

					grunt.file.write(destPath, content);
					var log = 'File ' + destPath + ' created with ' + Object.keys(preloadObject.modules).length + ' files';
					if (iPreloadOriginalSize && iPreloadCompressedSize && iPreloadOriginalSize !== iPreloadCompressedSize) {
						log += ' (' + maxmin({ length: iPreloadOriginalSize }, { length: iPreloadCompressedSize }) + ')';
					}
					grunt.log.writeln(log);

				});

			});

		});

	});
};
<commit_msg>fail gracefully when minification fails<commit_after>// Copyright 2016 SAP SE.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http: //www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific
// language governing permissions and limitations under the License.

'use strict';

var path = require('path');
var slash = require('slash');
var uglify = require('uglify-js');
var pd = require('pretty-data').pd;
var maxmin = require('maxmin');

var defaultResourcePatterns = [
	'**/*.js',
	'**/*.fragment.html',
	'**/*.fragment.json',
	'**/*.fragment.xml',
	'**/*.view.html',
	'**/*.view.json',
	'**/*.view.xml',
	'**/*.properties'
];

var copyrightCommentsPattern = /copyright|\(c\)|released under|license|\u00a9/i;
var xmlHtmlPrePattern = /<(?:\w+:)?pre>/;

module.exports = function (grunt) {

	grunt.registerMultiTask('openui5_preload', 'Create OpenUI5 preload files', function() {

		// Merge task-specific and/or target-specific options with these defaults.
		var options = this.options({
			resources: [],
			dest: null,
			compress: true
		});

		var resourceMap = {};

		// normalize string/object to array
		if (typeof options.resources === 'string' || (typeof options.resources === 'object' && !(options.resources instanceof Array))) {
			options.resources = [ options.resources ];
		}

		if (options.resources.length === 0) {
			grunt.fail.warn('"resources" option is not specified!');
			return;
		}

		grunt.verbose.subhead('Collecting resources');

		// process resources array
		options.resources.forEach(function(resource) {
			// transform string shorthand to object
			if (typeof resource === 'string') {
				resource = {
					cwd: resource
				};
			}

			if (typeof resource.prefix !== 'string') {
				resource.prefix = '';
			}

			resource.src = resource.src || defaultResourcePatterns;

			grunt.verbose.writeflags(resource, 'resource');

			grunt.file.expand({
				cwd: resource.cwd,
				dot: true,
				filter: 'isFile'
			}, resource.src).forEach(function(file) {
				var localFile = file;
				if (resource.prefix) {
					localFile = slash(path.join(resource.prefix, file));
				}
				var fullPath = path.join(resource.cwd, file);
				grunt.verbose.write('Collecting ' + localFile + ' (' + fullPath + ')...').ok();
				resourceMap[localFile] = {
					fullPath: fullPath,
					prefix: resource.prefix
				};
			});

		});

		var resourceFiles = Object.keys(resourceMap);

		if (resourceFiles.length === 0) {
			grunt.fail.warn('No files found. Check your "resources" option!');
			return;
		}

		var preloadData = this.data;
		if (!preloadData['components'] && !preloadData['libraries']) {
			grunt.fail.warn('No preload type specified. Please provide "components" and/or "libraries" in task target object!');
			return;
		}

		['components', 'libraries'].forEach(function(preloadType) {

			var preloadOptions = preloadData[preloadType];

			if (!preloadOptions) {
				return;
			}

			var preloadInfo = (preloadType === 'libraries') ? {
				moduleName: 'library-preload',
				ext: '.json',
				indicatorFile: 'library.js',
				processModuleName: function(moduleName) {
					return moduleName.replace(/\//g, '.');
				}
			} : {
				moduleName: 'Component-preload',
				ext: '.js',
				indicatorFile: 'Component.js',
				processContent: function(content) {
					return 'jQuery.sap.registerPreloadedModules(' + content + ');';
				}
			};

			if (preloadOptions === true) {
				preloadOptions = '**';
			}
			if (typeof preloadOptions === 'string') {
				var pattern = preloadOptions;
				preloadOptions = {};
				preloadOptions[pattern] = {};
			}

			var preloadOptionKeys = Object.keys(preloadOptions);

			if (preloadOptionKeys.length === 0) {
				grunt.log.writeflags(preloadOptions, 'preloadOptions');
				grunt.fail.warn('No valid options provided for "' + preloadType + '" preload!');
				return;
			}

			preloadOptionKeys.forEach(function(preloadPattern) {
				var preloadOption = preloadOptions[preloadPattern];
				var preloadFiles = grunt.file.match(preloadPattern + '/' + preloadInfo.indicatorFile, resourceFiles);

				if (preloadFiles.length < 1) {
					grunt.fail.warn('No "' + preloadInfo.indicatorFile + '" found for pattern "' + preloadPattern + '"!');
					return;
				}

				preloadFiles.forEach(function(preloadFile) {
					var preloadDir = path.dirname(preloadFile);
					var preloadModuleName = preloadDir + '/' + preloadInfo.moduleName;

					grunt.verbose.subhead('Creating preload module for ' + preloadFile);

					var preloadObject = {
						version: '2.0',
						name: preloadModuleName,
						modules: {}
					};

					if (typeof preloadInfo.processModuleName === 'function') {
						preloadObject.name = preloadInfo.processModuleName(preloadModuleName);
					} else {
						preloadObject.name = preloadModuleName;
					}

					var preloadPatterns = preloadOption.src ? preloadOption.src : [ preloadDir + '/**' ];
					if (typeof preloadPatterns === "string") {
						preloadPatterns = [ preloadPatterns ];
					}

					// Always exclude the corresponding preload file (Component-preload.js / library-preload.json)
					// Otherwise it might get included every time the build runs if src / dest are the same dir
					preloadPatterns.push('!' + preloadDir + '/' + preloadInfo.moduleName + preloadInfo.ext);

					var preloadFiles = grunt.file.match(preloadPatterns, resourceFiles);
					if (preloadFiles.length === 0) {
						var patternsString = (typeof preloadPatterns === 'string') ? preloadPatterns : preloadPatterns.join('", "');
						grunt.fail.warn('No files found for pattern(s): "' + patternsString + '"!');
						return;
					}

					var iPreloadOriginalSize = 0, iPreloadCompressedSize = 0;

					preloadFiles.forEach(function(preloadFile) {

						var fileName = resourceMap[preloadFile].fullPath;
						var fileContent = grunt.file.read(fileName);
						var fileExtension = path.extname(fileName);

						var iOriginalSize, iCompressedSize;

						if (options.compress) {

							iOriginalSize = fileContent.length;
							iPreloadOriginalSize += iOriginalSize;

							try {
								switch (fileExtension) {
								case '.js':
									// Javascript files are processed by Uglify
									fileContent = uglify.minify(fileContent, {
										fromString: true,
										warnings: grunt.option('verbose') === true,
										output: {
											comments: copyrightCommentsPattern
										}
									}).code;
									break;
								case '.json':
									// JSON is parsed and written to string again to remove unwanted white space
									fileContent = JSON.stringify(JSON.parse(fileContent));
									break;
								case '.xml':
									// For XML we use the pretty data

									// Do not minify if XML(View) contains an <*:pre> tag because whitespace of HTML <pre> should be preserved (should only happen rarely)
									if (!xmlHtmlPrePattern.test(fileContent)) {
										fileContent = pd.xmlmin(fileContent, false);
									}

									break;
								}
							} catch (e) {
								grunt.fail.warn('Failed to minify ' + fileName + '. This might be due to a syntax error in the file.');
							}

							iCompressedSize = fileContent.length;
							iPreloadCompressedSize += iCompressedSize;

						}

						if (grunt.option('verbose')) {
							var log = 'Adding ' + preloadFile;
							if (iOriginalSize && iCompressedSize && iOriginalSize !== iCompressedSize) {
								log += ' (' + maxmin({ length: iOriginalSize }, { length: iCompressedSize }) + ')';
							}
							grunt.verbose.writeln(log);
						}

						preloadObject.modules[preloadFile] = fileContent;
					});

					var content = JSON.stringify(preloadObject, null, '\t');
					if (typeof preloadInfo.processContent === 'function') {
						content = preloadInfo.processContent(content);
					}

					var destPath = options.dest;
					var preloadResourceInfo = resourceMap[preloadFile];
					if (preloadModuleName.indexOf(preloadResourceInfo.prefix) === 0) {
						destPath = path.join(destPath, preloadModuleName.substr(preloadResourceInfo.prefix.length));
					} else {
						destPath = path.join(destPath, preloadModuleName);
					}
					destPath += preloadInfo.ext;

					grunt.file.write(destPath, content);
					var log = 'File ' + destPath + ' created with ' + Object.keys(preloadObject.modules).length + ' files';
					if (iPreloadOriginalSize && iPreloadCompressedSize && iPreloadOriginalSize !== iPreloadCompressedSize) {
						log += ' (' + maxmin({ length: iPreloadOriginalSize }, { length: iPreloadCompressedSize }) + ')';
					}
					grunt.log.writeln(log);

				});

			});

		});

	});
};
<|endoftext|>


<commit_before>/*
Copyright (c) 2013, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://yuilibrary.com/license/
*/

var path = require('path'),
    fs = require('fs'),
    timethat = require('timethat'),
    cpr = require('cpr').cpr,
    crypto = require('crypto'),
    cssproc = require('cssproc'),
    rimraf = require('rimraf');

module.exports = function(grunt) {

    var VERSION = grunt.option('release-version') | '',
        BUILD = grunt.option('release-build'),
        start, startTime, head, sha;

    if (VERSION && (!BUILD || BUILD === 'git' || BUILD === 'sha')) {
        head = grunt.file.read('.git/HEAD').replace('ref: ', '').trim();
        if (head) {
            sha = grunt.file.read(path.join('.git/', head)).trim();
            if (sha) {
                sha = sha.substr(0, 7);
                grunt.log.warn('No --release-build passed, using sha: ' + sha);
                BUILD = sha;
                grunt.config.set('build', BUILD);
            }
        }
    }

    if (VERSION && VERSION !== '') {
        start = path.join(process.cwd(), 'release', VERSION);
        grunt.config.set('version', VERSION);
    }

    grunt.registerTask('release', 'Create a YUI Release', [
        'release-boot',
        'release-prebuild',
        'release-prep',
        'release-clean',
        'build',
        'dist',
        'cdn',
        'cdn-ssl',
        'release-validate',
        'release-zip',
        'release-finish'
    ]);
    grunt.registerTask('release-prebuild', 'Build and test before prep', [
        'build',
        'test'
    ]);

    grunt.registerTask('release-validate', 'Validate the release before zipping', function() {
        grunt.log.ok('Validating the Release files.');
        /*
            Only looks for common, predictable files to make sure the other
            tasks did their job.
        */
        var dirs = [
            'cdn',
            'cdn/build',
            'cdn/build/yui',
            'cdn/build/yui/yui-min.js',
            'cdn-ssl',
            'cdn-ssl/build',
            'cdn-ssl/build/yui',
            'cdn-ssl/build/yui/yui-min.js',
            'npm',
            'npm/package.json',
            'npm/index.js',
            'npm/debug.js',
            'dist',
            'dist/api',
            'dist/api/index.html',
            'dist/api/data.json',
            'dist/docs',
            'dist/docs/index.html',
            'dist/releasenotes',
            'dist/releasenotes/HISTORY.yui.md',
            'dist/tests',
            'dist/tests/yui/tests/unit/index.html',
            'dist/README.md',
            'dist/LICENSE.md'
        ],
        fail = function(file) {
            grunt.fail.fatal('Failed to find: ' + file);
        },
        base = path.join('release', VERSION);

        if (!grunt.file.exists(base)) {
            fail(base);
        } else {
            grunt.log.writeln('Found!: '.green + base.cyan);
        }

        dirs.forEach(function(d) {
            var file = path.join(base, d);
            if (!grunt.file.exists(file)) {
                fail(file);
            } else {
                grunt.log.writeln('Found!: '.green + file.cyan);
            }
        });

    });

    grunt.registerTask('release-zip', 'Zipping up', [
        'compress:dist',
        'compress:cdn',
        'compress:cdn-ssl',
        'release-md5'
    ]);

    grunt.registerTask('release-md5', 'Create MD5 for release file', function() {
        var done = this.async(),
            file = path.join(start, 'archives', 'yui_' + VERSION + '.zip'),
            md5File = file + '.MD5',
            shasum = crypto.createHash('md5'),
            s = fs.ReadStream(file),
            finish = function() {
                grunt.log.ok('Checking for release zips');
                var files = [
                    'akamai_' + VERSION + '.zip',
                    'akamaissl_' + VERSION + '.zip',
                    'yui_' + VERSION + '.zip',
                    'yui_' + VERSION + '.zip.MD5'
                ];
                files.forEach(function(f) {
                    var file = path.join('release', VERSION, 'archives', f);
                    if (grunt.file.exists(file)) {
                        grunt.log.writeln('Found!: '.green + ' ' + file.cyan);
                    } else {
                        grunt.fail.fatal('Failed to find: ' + file.red);
                    }
                });
                done();
            };

        s.on('data', function(d) { shasum.update(d); });
        s.on('end', function() {
            var md5 = shasum.digest('hex');
            grunt.log.ok('Setting MD5 for release to: ' + md5);
            grunt.log.writeln('');
            grunt.file.write(md5File, md5 + '\n');
            finish();
        });
    });

    grunt.registerTask('release-boot', 'Booting the YUI Release', function() {
        startTime = new Date();

        if (!VERSION) {
            grunt.fail.fatal('No version found, use --release-version=x.y.z');
        }

        if (!BUILD) {
            grunt.fail.fatal('No build number found, use --release-build=x.y.z');
        }

        grunt.log.ok('Preparing YUI release for ' + VERSION + ', building and testing raw');
    });

    grunt.registerTask('release-prep', 'Booting the YUI Release', function() {
        grunt.cli.options.release = true;
        grunt.log.ok('All tests passed, starting offical build now');
    });

    grunt.registerTask('release-finish', 'Complete the YUI Release', function() {
        var endTime = new Date();
        grunt.log.ok('YUI Release for ' + VERSION + ' completed in ' + timethat.calc(startTime, endTime));
    });

    grunt.registerTask('release-clean', 'Cleaning release', function() {
        grunt.log.write('Deleting release directory');
        var done = this.async();
        rimraf(start, function() {
            grunt.log.writeln('...OK');
            done();
        });
    });

    grunt.registerTask('cdn', 'Preparing CDN Release', function() {
        grunt.log.writeln('Preparing CDN Release');
        var done = this.async(),
            source = path.join(start, 'dist', 'build'),
            dest = path.join(start, 'cdn', 'build');

        grunt.log.write('Copying build');

        cpr(source, dest, function() {
            grunt.log.writeln('...OK');
            grunt.log.writeln('Processing CSS files');
            var count = 0,
                complete = 0;

            grunt.file.recurse(dest, function(file) {
                if (path.extname(file) === '.css') {
                    count++;
                    var str = grunt.file.read(file);
                    cssproc.parse({
                        root: path.join(dest, '../'),
                        path: file,
                        base: 'http:/'+'/yui.yahooapis.com/' + VERSION + '/'
                    }, str, function(err, data) {
                        if (str !== data) {
                            complete++;
                            grunt.file.write(file, data);
                        }
                    });
                }
            });

            grunt.log.writeln('Processed ' + complete + ' of ' + count + ' css files.');
            done();
        });

    });

    grunt.registerTask('cdn-ssl', 'Preparing CDN SSL Release', function() {
        grunt.log.writeln('Preparing CDN SSL Release');
        var done = this.async(),
            source = path.join(start, 'dist', 'build'),
            dest = path.join(start, 'cdn-ssl', 'build');

        grunt.log.write('Copying build');

        cpr(source, dest, function() {
            grunt.log.writeln('...OK');
            grunt.log.writeln('Processing CSS files');
            var count = 0,
                complete = 0;

            grunt.file.recurse(dest, function(file) {
                if (path.extname(file) === '.css') {
                    count++;
                    var str = grunt.file.read(file);
                    cssproc.parse({
                        root: path.join(dest, '../'),
                        path: file,
                        base: 'https:/'+'/yui-s.yahooapis.com/' + VERSION + '/'
                    }, str, function(err, data) {
                        if (str !== data) {
                            complete++;
                            grunt.file.write(file, data);
                        }
                    });
                }
            });

            grunt.log.writeln('Processed ' + complete + ' of ' + count + ' css files.');
            done();
        });
    });

};
<commit_msg>Fixed syntax error<commit_after>/*
Copyright (c) 2013, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://yuilibrary.com/license/
*/

var path = require('path'),
    fs = require('fs'),
    timethat = require('timethat'),
    cpr = require('cpr').cpr,
    crypto = require('crypto'),
    cssproc = require('cssproc'),
    rimraf = require('rimraf');

module.exports = function(grunt) {

    var VERSION = grunt.option('release-version') || '',
        BUILD = grunt.option('release-build'),
        start, startTime, head, sha;

    if (VERSION && (!BUILD || BUILD === 'git' || BUILD === 'sha')) {
        head = grunt.file.read('.git/HEAD').replace('ref: ', '').trim();
        if (head) {
            sha = grunt.file.read(path.join('.git/', head)).trim();
            if (sha) {
                sha = sha.substr(0, 7);
                grunt.log.warn('No --release-build passed, using sha: ' + sha);
                BUILD = sha;
                grunt.config.set('build', BUILD);
            }
        }
    }

    if (VERSION && VERSION !== '') {
        start = path.join(process.cwd(), 'release', VERSION);
        grunt.config.set('version', VERSION);
    }

    grunt.registerTask('release', 'Create a YUI Release', [
        'release-boot',
        'release-prebuild',
        'release-prep',
        'release-clean',
        'build',
        'dist',
        'cdn',
        'cdn-ssl',
        'release-validate',
        'release-zip',
        'release-finish'
    ]);
    grunt.registerTask('release-prebuild', 'Build and test before prep', [
        'build',
        'test'
    ]);

    grunt.registerTask('release-validate', 'Validate the release before zipping', function() {
        grunt.log.ok('Validating the Release files.');
        /*
            Only looks for common, predictable files to make sure the other
            tasks did their job.
        */
        var dirs = [
            'cdn',
            'cdn/build',
            'cdn/build/yui',
            'cdn/build/yui/yui-min.js',
            'cdn-ssl',
            'cdn-ssl/build',
            'cdn-ssl/build/yui',
            'cdn-ssl/build/yui/yui-min.js',
            'npm',
            'npm/package.json',
            'npm/index.js',
            'npm/debug.js',
            'dist',
            'dist/api',
            'dist/api/index.html',
            'dist/api/data.json',
            'dist/docs',
            'dist/docs/index.html',
            'dist/releasenotes',
            'dist/releasenotes/HISTORY.yui.md',
            'dist/tests',
            'dist/tests/yui/tests/unit/index.html',
            'dist/README.md',
            'dist/LICENSE.md'
        ],
        fail = function(file) {
            grunt.fail.fatal('Failed to find: ' + file);
        },
        base = path.join('release', VERSION);

        if (!grunt.file.exists(base)) {
            fail(base);
        } else {
            grunt.log.writeln('Found!: '.green + base.cyan);
        }

        dirs.forEach(function(d) {
            var file = path.join(base, d);
            if (!grunt.file.exists(file)) {
                fail(file);
            } else {
                grunt.log.writeln('Found!: '.green + file.cyan);
            }
        });

    });

    grunt.registerTask('release-zip', 'Zipping up', [
        'compress:dist',
        'compress:cdn',
        'compress:cdn-ssl',
        'release-md5'
    ]);

    grunt.registerTask('release-md5', 'Create MD5 for release file', function() {
        var done = this.async(),
            file = path.join(start, 'archives', 'yui_' + VERSION + '.zip'),
            md5File = file + '.MD5',
            shasum = crypto.createHash('md5'),
            s = fs.ReadStream(file),
            finish = function() {
                grunt.log.ok('Checking for release zips');
                var files = [
                    'akamai_' + VERSION + '.zip',
                    'akamaissl_' + VERSION + '.zip',
                    'yui_' + VERSION + '.zip',
                    'yui_' + VERSION + '.zip.MD5'
                ];
                files.forEach(function(f) {
                    var file = path.join('release', VERSION, 'archives', f);
                    if (grunt.file.exists(file)) {
                        grunt.log.writeln('Found!: '.green + ' ' + file.cyan);
                    } else {
                        grunt.fail.fatal('Failed to find: ' + file.red);
                    }
                });
                done();
            };

        s.on('data', function(d) { shasum.update(d); });
        s.on('end', function() {
            var md5 = shasum.digest('hex');
            grunt.log.ok('Setting MD5 for release to: ' + md5);
            grunt.log.writeln('');
            grunt.file.write(md5File, md5 + '\n');
            finish();
        });
    });

    grunt.registerTask('release-boot', 'Booting the YUI Release', function() {
        startTime = new Date();

        if (!VERSION) {
            grunt.fail.fatal('No version found, use --release-version=x.y.z');
        }

        if (!BUILD) {
            grunt.fail.fatal('No build number found, use --release-build=x.y.z');
        }

        grunt.log.ok('Preparing YUI release for ' + VERSION + ', building and testing raw');
    });

    grunt.registerTask('release-prep', 'Booting the YUI Release', function() {
        grunt.cli.options.release = true;
        grunt.log.ok('All tests passed, starting offical build now');
    });

    grunt.registerTask('release-finish', 'Complete the YUI Release', function() {
        var endTime = new Date();
        grunt.log.ok('YUI Release for ' + VERSION + ' completed in ' + timethat.calc(startTime, endTime));
    });

    grunt.registerTask('release-clean', 'Cleaning release', function() {
        grunt.log.write('Deleting release directory');
        var done = this.async();
        rimraf(start, function() {
            grunt.log.writeln('...OK');
            done();
        });
    });

    grunt.registerTask('cdn', 'Preparing CDN Release', function() {
        grunt.log.writeln('Preparing CDN Release');
        var done = this.async(),
            source = path.join(start, 'dist', 'build'),
            dest = path.join(start, 'cdn', 'build');

        grunt.log.write('Copying build');

        cpr(source, dest, function() {
            grunt.log.writeln('...OK');
            grunt.log.writeln('Processing CSS files');
            var count = 0,
                complete = 0;

            grunt.file.recurse(dest, function(file) {
                if (path.extname(file) === '.css') {
                    count++;
                    var str = grunt.file.read(file);
                    cssproc.parse({
                        root: path.join(dest, '../'),
                        path: file,
                        base: 'http:/'+'/yui.yahooapis.com/' + VERSION + '/'
                    }, str, function(err, data) {
                        if (str !== data) {
                            complete++;
                            grunt.file.write(file, data);
                        }
                    });
                }
            });

            grunt.log.writeln('Processed ' + complete + ' of ' + count + ' css files.');
            done();
        });

    });

    grunt.registerTask('cdn-ssl', 'Preparing CDN SSL Release', function() {
        grunt.log.writeln('Preparing CDN SSL Release');
        var done = this.async(),
            source = path.join(start, 'dist', 'build'),
            dest = path.join(start, 'cdn-ssl', 'build');

        grunt.log.write('Copying build');

        cpr(source, dest, function() {
            grunt.log.writeln('...OK');
            grunt.log.writeln('Processing CSS files');
            var count = 0,
                complete = 0;

            grunt.file.recurse(dest, function(file) {
                if (path.extname(file) === '.css') {
                    count++;
                    var str = grunt.file.read(file);
                    cssproc.parse({
                        root: path.join(dest, '../'),
                        path: file,
                        base: 'https:/'+'/yui-s.yahooapis.com/' + VERSION + '/'
                    }, str, function(err, data) {
                        if (str !== data) {
                            complete++;
                            grunt.file.write(file, data);
                        }
                    });
                }
            });

            grunt.log.writeln('Processed ' + complete + ' of ' + count + ' css files.');
            done();
        });
    });

};
<|endoftext|>


<commit_before>"use strict";

/**
Import an orthogonal tilemap from
 * Tiled: Map Editor and draw on the screen.

 *
To Do

 *

 *
Image Layer

 *
Ellipse and Polygon Objects

 *

 * @module Import From Tiled
 */

/** @function ImportTilemap
 * @param {Object} file JSON file exported from Tiled. This should be required in a scene enter
 * script and passed to the function.
 * @param {EntityPool} entities EntityPool from game.entities
 */
function ImportTilemap(file, entities) { // eslint-disable-line no-unused-vars

	var tile, image, image_index, tile_pos, cols, tileset, tileset_index = 0;
	var layer, object, entity;

	for (var i = 0; i < file.layers.length; i++) {
		layer = file.layers[i];

		// Render Tile Layers
		if (layer.type == "tilelayer") {
			for (j = 0; j < layer.data.length; j++) {

				// Select tileset index based on firstgid and image index
				// Set image index minus firstgid for positioning math
				for (var k = 0; k < file.tilesets.length; k++) {
					if (layer.data[j] > file.tilesets[k].firstgid) {
						tileset_index = k;
					}
				}
				cols = file.tilesets[tileset_index].imagewidth / file.tilesets[tileset_index].tilewidth;
				image_index = layer.data[j] - file.tilesets[tileset_index].firstgid;
				tileset = file.tilesets[tileset_index];

				if (image_index >= 0) {

					// Create tile and get properties
					tile = entities.create();
					entities.set(tile, "name", "tile");
					entities.set(tile, "tile", true);
					entities.set(tile, "image", { "name": "" });
					entities.set(tile, "position", { "x": 0, "y": 0 });
					image = entities.get(tile, "image");
					tile_pos = entities.get(tile, "position");

					// Position based on index
					tile_pos.x = (j % file.width) * file.tilewidth;
					tile_pos.y = Math.floor(j / file.width) * file.tileheight;

					// Character position z: 1 so anything without background true will layer over player
					tile_pos.z = (layer.properties.Background == "True") ? -1 : 2;

					// Select which "tile" of the tileset image to render
					image.name = tileset.image;
					image.sourceWidth = tileset.tilewidth;
					image.sourceHeight = tileset.tileheight;
					image.destinationWidth = tileset.tilewidth;
					image.destinationHeight = tileset.tileheight;
					image.sourceX = (image_index % cols) * tileset.tilewidth + ((image_index % cols) * tileset.spacing) + tileset.margin;
					image.sourceY = Math.floor(image_index / cols) * tileset.tileheight + (Math.floor(image_index / cols) * tileset.spacing) + tileset.margin;

				}
			}
		}

		/**
		 * @member {Entity} Object Entities
		 *
Create Entity with size and position components

		 *
Collidable: True or False
Add collision component to entity.
		 * Currently collisions are handled as a simulation system in the project.

		 *
Spawn: True or False
Creates an entity with a "spawn" boolean
		 * component allowing you to use game.entities.find("spawn"); to find the spawn point for this map.

		 *
All other properties end up in a "tiled_properties" component to be handled on a per-game basis.
		 */
		// Loop object layer for collisions and spawn point
		if (layer.type == "objectgroup") {
			for (var j = 0; j < layer.objects.length; j++) {
				object = layer.objects[j];
				entity = entities.create();
				entities.set(entity, "size", { "width": object.width, "height": object.height });
				entities.set(entity, "position", { "x": object.x, "y": object.y });
				Object.keys(object.properties).forEach(function(key) {
					if (!isNaN(object.properties[key])) {
						object.properties[key] = parseInt(object.properties[key], 10);
					}
					if (new String(object.properties[key]).toLowerCase() == "true" || object.properties[key] == "1") {
						object.properties[key] = true;
					}
					if (new String(object.properties[key]).toLowerCase() == "false" || object.properties[key] == "0") {
						object.properties[key] = false;
					}
				});
				entities.set(entity, "tiled_properties", object.properties);

				// Collision box prefabs
				if (object.properties.Collidable) {
					entities.set(entity, "name", "collider");
					entities.set(entity, "collisions", []);
				}

				// Spawn points
				if (object.properties.Spawn) {
					entities.set(entity, "name", "spawn");
					entities.set(entity, "spawn", true);
				}
			}
		}
	}

	/**
	 * @member {Entity} Container Entity
	 * Created automatically allowing you to use
	 * game.entities.find("container"); to get a constrainPosition ID

	 */
	var map_size = {
		"width": file.width * file.tilewidth,
		"height": file.height * file.tileheight
	};
	var container = entities.create();
	entities.set(container, "name", "container");
	entities.set(container, "container", true);
	entities.set(container, "position", { "x": 0, "y": 0 });
	entities.set(container, "size", map_size);

}

module.exports = ImportTilemap;
<commit_msg>change tiled_properties component to camel casing to match other component naming and delete Spawn and Collidable properties from the tiledProperties component since they automatically add the correct components<commit_after>"use strict";

/**
Import an orthogonal tilemap from
 * Tiled: Map Editor and draw on the screen.

 *
To Do

 *

 *
Image Layer

 *
Ellipse and Polygon Objects

 *

 * @module Import From Tiled
 */

/** @function ImportTilemap
 * @param {Object} file JSON file exported from Tiled. This should be required in a scene enter
 * script and passed to the function.
 * @param {EntityPool} entities EntityPool from game.entities
 */
function ImportTilemap(file, entities) { // eslint-disable-line no-unused-vars

	var tile, image, image_index, tile_pos, cols, tileset, tileset_index = 0;
	var layer, object, entity;

	for (var i = 0; i < file.layers.length; i++) {
		layer = file.layers[i];

		// Render Tile Layers
		if (layer.type == "tilelayer") {
			for (j = 0; j < layer.data.length; j++) {

				// Select tileset index based on firstgid and image index
				// Set image index minus firstgid for positioning math
				for (var k = 0; k < file.tilesets.length; k++) {
					if (layer.data[j] > file.tilesets[k].firstgid) {
						tileset_index = k;
					}
				}
				cols = file.tilesets[tileset_index].imagewidth / file.tilesets[tileset_index].tilewidth;
				image_index = layer.data[j] - file.tilesets[tileset_index].firstgid;
				tileset = file.tilesets[tileset_index];

				if (image_index >= 0) {

					// Create tile and get properties
					tile = entities.create();
					entities.set(tile, "name", "tile");
					entities.set(tile, "tile", true);
					entities.set(tile, "image", { "name": "" });
					entities.set(tile, "position", { "x": 0, "y": 0 });
					image = entities.get(tile, "image");
					tile_pos = entities.get(tile, "position");

					// Position based on index
					tile_pos.x = (j % file.width) * file.tilewidth;
					tile_pos.y = Math.floor(j / file.width) * file.tileheight;

					// Character position z: 1 so anything without background true will layer over player
					tile_pos.z = (layer.properties.Background == "True") ? -1 : 2;

					// Select which "tile" of the tileset image to render
					image.name = tileset.image;
					image.sourceWidth = tileset.tilewidth;
					image.sourceHeight = tileset.tileheight;
					image.destinationWidth = tileset.tilewidth;
					image.destinationHeight = tileset.tileheight;
					image.sourceX = (image_index % cols) * tileset.tilewidth + ((image_index % cols) * tileset.spacing) + tileset.margin;
					image.sourceY = Math.floor(image_index / cols) * tileset.tileheight + (Math.floor(image_index / cols) * tileset.spacing) + tileset.margin;

				}
			}
		}

		/**
		 * @member {Entity} Object Entities
		 *
Create Entity with size and position components

		 *
Collidable: True or False
Add collision component to entity.
		 * Currently collisions are handled as a simulation system in the project.

		 *
Spawn: True or False
Creates an entity with a "spawn" boolean
		 * component allowing you to use game.entities.find("spawn"); to find the spawn point for this map.

		 *
All other properties end up in a "tiledProperties" component to be handled on a per-game basis.
		 */
		// Loop object layer for collisions and spawn point
		if (layer.type == "objectgroup") {
			for (var j = 0; j < layer.objects.length; j++) {
				object = layer.objects[j];
				entity = entities.create();
				entities.set(entity, "size", { "width": object.width, "height": object.height });
				entities.set(entity, "position", { "x": object.x, "y": object.y });
				Object.keys(object.properties).forEach(function(key) {
					if (!isNaN(object.properties[key])) {
						object.properties[key] = parseInt(object.properties[key], 10);
					}
					if (new String(object.properties[key]).toLowerCase() == "true" || object.properties[key] == "1") {
						object.properties[key] = true;
					}
					if (new String(object.properties[key]).toLowerCase() == "false" || object.properties[key] == "0") {
						object.properties[key] = false;
					}
				});

				// Collision box entities
				if (object.properties.Collidable) {
					entities.set(entity, "collisions", []);
					delete object.properties.Collidable;
				}

				// Spawn points
				if (object.properties.Spawn) {
					entities.set(entity, "spawn", true);
					delete object.properties.Spawn;
				}

				entities.set(entity, "tiledProperties", object.properties);

			}
		}
	}

	/**
	 * @member {Entity} Container Entity
	 * Created automatically allowing you to use
	 * game.entities.find("container"); to get a constrainPosition ID

	 */
	var map_size = {
		"width": file.width * file.tilewidth,
		"height": file.height * file.tileheight
	};
	var container = entities.create();
	entities.set(container, "name", "container");
	entities.set(container, "container", true);
	entities.set(container, "position", { "x": 0, "y": 0 });
	entities.set(container, "size", map_size);

}

module.exports = ImportTilemap;
<|endoftext|>


<commit_before>/*
 * grunt-shampoo
 * https://github.com/soapcreative/grunt-shampoo
 *
 * Copyright (c) 2014 Soap Creative
 * Licensed under the MIT license.
 */

'use strict';

var request = require("request"),
    sha256 = require("sha256"),
    fs = require("fs"),
    knox = require("knox"),
    crypto = require('crypto'),
    rc = require('rc'),
    DecompressZip = require('decompress-zip'),
    fs = require('fs'),
    path = require('path'),
    util = require('util'),
    url = require('url'),
    querystring = require('querystring'),
    mkdirp = require('mkdirp'),
    _ = require('lodash');

var HTTP_OK = 200,
    HTTP_NOT_MODIFIED = 304;

var ZIP_FOLDER_NAME = "content-backups",
    ZIP_FILE_NAME_PREFIX = "content-dump-";

var DEFAULT_MAX_CONNECTIONS = 8;

module.exports = function( grunt ) {

  grunt.registerMultiTask( "shampoo", "Retrieve content from the Shampoo CMS API on shampoo.io.", function() {

    var thisTask = this;

    function createPath(path, options, callback) {
      if (typeof options === 'function') {
        callback = options;
        options = null;
      }
      mkdirp(path, options, function (error, created) {
        if (error) {
          grunt.log.error("Couldn't create %j: %s", path, error);
        }
        callback(error, created);
      });
    }

    function castToArray(thing) {
      if (!thing) {
        return [ ];
      }
      if (Array.isArray(thing)) {
        return thing;
      }
      return [ thing ];
    }

    function responseOk(requestName, error, response, allowExtraStatusCodes) {
      var allowStatusCodes = [ HTTP_OK ].concat(castToArray(allowExtraStatusCodes)),
        formatArgs = [ "" ],
        ok = true;

      if (requestName) {
        formatArgs[0] += "%j: ";
        formatArgs.push(requestName);
      }

      if (error) {
        formatArgs[0] += "Request error: %s";
        formatArgs.push(error);
        ok = false;
      } else if (!response) {
        formatArgs[0] += "No response";
        ok = false;
      } else if (allowStatusCodes.indexOf(response.statusCode) < 0) {
        formatArgs[0] += "Unexpected status code: %s";
        formatArgs.push(response.statusCode);
        ok = false;
      }

      if (!ok) {
        grunt.log.error.apply(grunt.log, formatArgs);
      }
      return ok;
    }

    function makeClient( options ) {
      return knox.createClient( _.pick(options, [
        'region', 'endpoint', 'port', 'key', 'secret', 'access', 'bucket', 'secure', 'headers', 'style'
      ]));
    }

    function isMediaAssetUrl(assetUrl) {
      // a URL is a media asset URL if its scheme/protocol is http or https,
      // and its hostname is a subdomain of amazonaws.com.
      return Boolean(
        assetUrl &&
        /^https?:$/i .test(assetUrl.protocol) &&
        /\.amazonaws\.com$/i .test(assetUrl.hostname)
      );
    }

    function getMediaAssetPath(assetUrlString) {
      var assetUrl;
      try {
        assetUrl = url.parse(assetUrlString);
        if (isMediaAssetUrl(assetUrl)) {
          var pathname = assetUrl.pathname;
          if (pathname.charAt(0) === "/") {
            pathname = pathname.slice(1);
          }
          // url.parse automatically url-escapes characters, but we need to
          // reverse that for passing to the knox client, as well as for saving
          // locally
          return decodeURI(pathname);
        }
      } catch (error) { } // url.parse failed, so just fall through to return null
      return null;
    }

    function getMediaAssets( obj, mediaCwd ) {

      var objQueue = [ obj ],
        prefixQueue = [ "[Root]" ],
        remotePaths = { };

      while (objQueue.length > 0) {
        var thing = objQueue.shift(),
          prefix = prefixQueue.shift();

        // don't need to type check here, only objects and arrays will iterate,
        // which is what we want
        _.forOwn(thing, function (value, key) {
          var keyPath = prefix + "." + key;
          if (typeof value === "string") {
            var assetPath = getMediaAssetPath(value);

            if (assetPath != null) {
              // rewrite the property in the JSON with the local path
              thing[key] = path.join(mediaCwd, assetPath);

              grunt.verbose.writeln(
                "Rewriting %s\n" +
                "  old: %j\n" +
                "  new: %j\n",
                keyPath, value, thing[key]
              );

              // record the remote path relative to its root downloading
              // setting it as an object property means dupes are naturally
              // eliminated
              remotePaths[assetPath] = true;
            }
          } else {
            objQueue.push(value);
            prefixQueue.push(keyPath);
          }
        });
      }

      return Object.keys(remotePaths);
    }

    function requestJson(url, options, done) {
      grunt.verbose.writeln("Downloading JSON");

      request(url, function( error, response, body ) {
        var jsonContent = null;
        if (responseOk(url, error, response)) {
          try {
            jsonContent = JSON.parse(body);
          } catch (parseError) {
            grunt.log.error("Error parsing %j as JSON: %s", url, parseError);
          }
        }

        if (jsonContent && options.out) {
          if( options.mediaOut ) {

            saveMedia(options, jsonContent, done);

          } else {

            writeJsonFile( options.out, jsonContent );
            done();
            return;

          }
        }

        // we reach here if request failed, json parse failed, or if options.out
        // is not set
        done();
      });

    }

    function generateZipFileName() {
      return ZIP_FILE_NAME_PREFIX + Date.now() + ".zip";
    }

    function requestZip(url, options, done) {

      var zipPath = path.join(
        options.zipOut, ZIP_FOLDER_NAME, generateZipFileName());

      createPath(path.dirname(zipPath), null, function (mkdirError) {
        if (mkdirError) {
          done(false);
          return;
        }

        grunt.verbose.writeln("Downloading zip");
        request(url, function(error, response, body) {

          if (responseOk(url, error, response)) {
            var unzipper = new DecompressZip(zipPath);

            unzipper.on("extract", function (log) {

              //on extraction of the zip, check if mediaOut is set, if so, loop through all the unzipped files, and grab down the neccesary media.
              if(options.mediaOut !== "") {

                for(var key in log) {
                  var unzippedFile = options.zipOut + log[key].deflated;

                  fs.readFile( unzippedFile, function ( err, data ) {

                    var body = JSON.parse(data);
                    //override the out to match zipOut, as json files get written to options.out
                    options.out = unzippedFile;
                    saveMedia(options, body, done);

                  });

                }

              } else {

                done();

              }

            });

            unzipper.on("error", function(error) {
              grunt.log.error("An error occurred unzipping the file %j: %s", zipPath, error);
              done(false);
            });

            unzipper.extract({
              path: options.zipOut
            });
          } else {
            done(false);
          }

        }).pipe(fs.createWriteStream(zipPath));

      });

    }

    function saveMedia(options, body, done) {

      var mediaAssets = getMediaAssets( body, options.mediaCwd );
      var client = makeClient( options.aws );

      grunt.verbose.writeln("Media queue is:");
      mediaAssets.forEach(function (p) {
        grunt.verbose.writeln("  %j", p);
      });

      var loadCounter = 0;
      var next = function() {
        loadCounter--;
        fillQueue();
      };

      var fillQueue = function() {
        if (mediaAssets.length === 0 && loadCounter === 0) {
          writeJsonFile( options.out, body );
          done();
        } else {
          while (mediaAssets.length > 0 && loadCounter < options.maxConnections) {
            loadCounter++;
            verifyDownload( client, mediaAssets.shift(), options.mediaOut, next );
          }
        }
      };

      fillQueue();
    }

    function verifyDownload( client, remotePath, mediaOut, doneCallback ) {

      var localPath = path.join(mediaOut, remotePath);
      var localHash = null;

      grunt.verbose.writeln("Verifying %j -> %j", remotePath, localPath);
      fs.readFile( localPath, function ( err, data ) {
        if (err) {
          grunt.verbose.error("Etag calculation of local file failed: %s", err);
        } else {
          localHash = crypto.createHash('md5').update(data).digest('hex');
        }

        createPath(path.dirname(localPath), function (error) {
          if (!error) {
            downloadFile(client, remotePath, localPath, localHash, doneCallback);
          }
        });
      });

    }

    function writeJsonFile(out, body) {
      grunt.log.subhead( "Retrieving content..." );
      grunt.log.write( out + " ");
      grunt.log.ok( "saved" );
      grunt.file.write(out, JSON.stringify(body, null, '\t'));

    }

    function downloadFile(client, src, dest, etag, doneCallback) {
      var requestHeaders = { };

      grunt.verbose.writeln("S3 GET %j", src);

      if (etag) {
        grunt.verbose.writeln("If-None-Match: %s", etag);
        requestHeaders["If-None-Match"] = etag;
      }

      client.getFile(src, requestHeaders, function (err, res) {
        if (responseOk(src, err, res, HTTP_NOT_MODIFIED)) {
          var file = fs.createWriteStream(dest);
          file.on("error", function(e) {
            logError("Error writing: %s", e);
            doneCallback();
          });

          res
            .on('error', function (err) {
              logError("Error reading %j: %s", src, err);
              doneCallback();
            })
            .on('end', function () {
              logOk( "downloaded" );
              doneCallback();
            });

          res.pipe(file);
        } else {
          doneCallback();
        }
      });

    }

    function requestFiles(options, gruntCallback) {
      grunt.log.subhead( "Retrieving files..." );
      var url = createApiUrl(options, createRequestId());
      grunt.verbose.writeln("Url is %j", url);

      if (isZipQuery(options.query)) {
        grunt.verbose.writeln("Zip job");
        requestZip(url, options, gruntCallback);
      } else {
        grunt.verbose.writeln("JSON job");
        requestJson(url, options, gruntCallback);
      }
    }

    function isZipQuery(query) {
      return query.indexOf("dump/zip/") === 0;
    }

    function normalizeDir(path) {
      // TODO: change path string operations to use path lib, and make this
      // function unnecessary
      if (path == null) {
        return null;
      }
      path = String(path);
      if (path === "") {
        return "./";
      }
      if (path.slice(-1) !== "/") {
        return path + "/";
      }
      return path;
    }

    function getOptions() {
      // Mix in default options, .shampoorc file
      var options = rc("shampoo", thisTask.options({
        api: 1,
        query: "dump/json/single-file",
        out: "data/content.json",
        mediaOut: null,
        mediaCwd: null,
        maxConnections: DEFAULT_MAX_CONNECTIONS
      }));

      var messages = [ ];
      var missing = { };
      var required = [ "key", "secret", "domain", "query", "out" ];

      if (isZipQuery(options.query)) {
        required.push("zipOut");
      }

      required.forEach(function (optionName) {
        if (!options[optionName]) {
          missing[optionName] = true;
        }
      });

      var missingArray = Object.keys(missing);
      if (missingArray.length > 0) {
        messages.push("The following required options are not set: " +
          missingArray.join(", "));
      }

      if (missing.key || missing.secret) {
        messages.push("Values for 'key' and 'secret' are found in your Shampoo account under Settings.");
      }

      if (missing.zipOut) {
        messages.push(util.format(
          "The query %j returns a zip file. This requires the 'zipOut' option to be set.",
          options.query
        ));
      }

      options.mediaOut = normalizeDir(options.mediaOut);
      if (options.mediaCwd == null) {
        options.mediaCwd = options.mediaOut;
      } else {
        options.mediaCwd = normalizeDir(options.mediaCwd);
      }

      var parsedMaxConnections = parseInt(options.maxConnections, 10);
      if (isNaN(options.maxConnections)) {
        messages.push(util.format(
          "Invalid value for maxConnections: %j. Assuming default of %d.",
          options.maxConnections, DEFAULT_MAX_CONNECTIONS
        ));
        parsedMaxConnections = DEFAULT_MAX_CONNECTIONS;
      } else if (parsedMaxConnections < 1) {
        messages.push(
          "Value for maxConnections must be 1 or greater. Assuming 1.");
        parsedMaxConnections = 1;
      }

      options.maxConnections = parsedMaxConnections;

      return {
        options: options,
        messages: messages,
        ok: messages.length === 0
      };
    }

    function createRequestId() {
      return Date.now().toString(36) +
        (Math.random() * 9007199254740992).toString(36);
    }

    function createToken(secret, key, requestId) {
      return sha256("" + secret + key + requestId);
    }

    function createApiUrl(options, requestId) {
      var url = [
          options.https ? "https" : "http",
          "://",
          options.domain,
          "/api/v",
          options.api,
          "/",
          options.query
        ].join("");

      var queryParams = _.merge({
          requestId: requestId,
          token: createToken(options.secret, options.key, requestId)
        }, options.params || {});

      return url + "?" + querystring.stringify(queryParams);
    }

    function main() {
      var optionResult = getOptions();
      var messagesString = optionResult.messages.join("\n");
      var done = thisTask.async();

      if (optionResult.ok) {
        grunt.log.writeln(messagesString);
        requestFiles(optionResult.options, done);
      } else {
        grunt.log.error(messagesString);
        done(false);
      }

    }

    return main();
  });
};
<commit_msg>also have a common JSON parse routine that catches and logs errors<commit_after>/*
 * grunt-shampoo
 * https://github.com/soapcreative/grunt-shampoo
 *
 * Copyright (c) 2014 Soap Creative
 * Licensed under the MIT license.
 */

'use strict';

var request = require("request"),
    sha256 = require("sha256"),
    fs = require("fs"),
    knox = require("knox"),
    crypto = require('crypto'),
    rc = require('rc'),
    DecompressZip = require('decompress-zip'),
    fs = require('fs'),
    path = require('path'),
    util = require('util'),
    url = require('url'),
    querystring = require('querystring'),
    mkdirp = require('mkdirp'),
    _ = require('lodash');

var HTTP_OK = 200,
    HTTP_NOT_MODIFIED = 304;

var ZIP_FOLDER_NAME = "content-backups",
    ZIP_FILE_NAME_PREFIX = "content-dump-";

var DEFAULT_MAX_CONNECTIONS = 8;

module.exports = function( grunt ) {

  grunt.registerMultiTask( "shampoo", "Retrieve content from the Shampoo CMS API on shampoo.io.", function() {

    var thisTask = this;

    function createPath(path, options, callback) {
      if (typeof options === 'function') {
        callback = options;
        options = null;
      }
      mkdirp(path, options, function (error, created) {
        if (error) {
          grunt.log.error("Couldn't create %j: %s", path, error);
        }
        callback(error, created);
      });
    }

    function castToArray(thing) {
      if (!thing) {
        return [ ];
      }
      if (Array.isArray(thing)) {
        return thing;
      }
      return [ thing ];
    }

    function formatArgsPrefix(prefix) {
      return prefix ?
        [ "%j: ", prefix ] :
        [ "" ];
    }

    function responseOk(requestName, error, response, allowExtraStatusCodes) {
      var allowStatusCodes = [ HTTP_OK ].concat(castToArray(allowExtraStatusCodes)),
        formatArgs = formatArgsPrefix(requestName),
        ok = true;

      if (error) {
        formatArgs[0] += "Request error: %s";
        formatArgs.push(error);
        ok = false;
      } else if (!response) {
        formatArgs[0] += "No response";
        ok = false;
      } else if (allowStatusCodes.indexOf(response.statusCode) < 0) {
        formatArgs[0] += "Unexpected status code: %s";
        formatArgs.push(response.statusCode);
        ok = false;
      }

      if (!ok) {
        grunt.log.error.apply(grunt.log, formatArgs);
      }
      return ok;
    }

    function tryParseJson(requestName, text) {
      try {
        return JSON.parse(text);
      } catch (error) {
        var formatArgs = formatArgsPrefix(requestName);
        formatArgs[0] += "Error parsing JSON: %s";
        formatArgs.push(error);
        grunt.log.error.apply(grunt.log, formatArgs);
        return null;
      }
    }

    function makeClient( options ) {
      return knox.createClient( _.pick(options, [
        'region', 'endpoint', 'port', 'key', 'secret', 'access', 'bucket', 'secure', 'headers', 'style'
      ]));
    }

    function isMediaAssetUrl(assetUrl) {
      // a URL is a media asset URL if its scheme/protocol is http or https,
      // and its hostname is a subdomain of amazonaws.com.
      return Boolean(
        assetUrl &&
        /^https?:$/i .test(assetUrl.protocol) &&
        /\.amazonaws\.com$/i .test(assetUrl.hostname)
      );
    }

    function getMediaAssetPath(assetUrlString) {
      var assetUrl;
      try {
        assetUrl = url.parse(assetUrlString);
        if (isMediaAssetUrl(assetUrl)) {
          var pathname = assetUrl.pathname;
          if (pathname.charAt(0) === "/") {
            pathname = pathname.slice(1);
          }
          // url.parse automatically url-escapes characters, but we need to
          // reverse that for passing to the knox client, as well as for saving
          // locally
          return decodeURI(pathname);
        }
      } catch (error) { } // url.parse failed, so just fall through to return null
      return null;
    }

    function getMediaAssets( obj, mediaCwd ) {

      var objQueue = [ obj ],
        prefixQueue = [ "[Root]" ],
        remotePaths = { };

      while (objQueue.length > 0) {
        var thing = objQueue.shift(),
          prefix = prefixQueue.shift();

        // don't need to type check here, only objects and arrays will iterate,
        // which is what we want
        _.forOwn(thing, function (value, key) {
          var keyPath = prefix + "." + key;
          if (typeof value === "string") {
            var assetPath = getMediaAssetPath(value);

            if (assetPath != null) {
              // rewrite the property in the JSON with the local path
              thing[key] = path.join(mediaCwd, assetPath);

              grunt.verbose.writeln(
                "Rewriting %s\n" +
                "  old: %j\n" +
                "  new: %j\n",
                keyPath, value, thing[key]
              );

              // record the remote path relative to its root downloading
              // setting it as an object property means dupes are naturally
              // eliminated
              remotePaths[assetPath] = true;
            }
          } else {
            objQueue.push(value);
            prefixQueue.push(keyPath);
          }
        });
      }

      return Object.keys(remotePaths);
    }

    function requestJson(url, options, done) {
      grunt.verbose.writeln("Downloading JSON");

      request(url, function( error, response, body ) {
        var jsonContent;
        if (responseOk(url, error, response)) {
          jsonContent = tryParseJson(body);
        }

        if (jsonContent && options.out) {
          if( options.mediaOut ) {

            saveMedia(options, jsonContent, done);

          } else {

            writeJsonFile( options.out, jsonContent );
            done();
            return;

          }
        }

        // we reach here if request failed, json parse failed, or if options.out
        // is not set
        done();
      });

    }

    function generateZipFileName() {
      return ZIP_FILE_NAME_PREFIX + Date.now() + ".zip";
    }

    function requestZip(url, options, done) {

      var zipPath = path.join(
        options.zipOut, ZIP_FOLDER_NAME, generateZipFileName());

      createPath(path.dirname(zipPath), null, function (mkdirError) {
        if (mkdirError) {
          done(false);
          return;
        }

        grunt.verbose.writeln("Downloading zip");
        request(url, function(error, response, body) {

          if (responseOk(url, error, response)) {
            var unzipper = new DecompressZip(zipPath);

            unzipper.on("extract", function (log) {

              //on extraction of the zip, check if mediaOut is set, if so, loop through all the unzipped files, and grab down the neccesary media.
              if(options.mediaOut !== "") {

                for(var key in log) {
                  var unzippedFile = options.zipOut + log[key].deflated;

                  fs.readFile( unzippedFile, function ( err, data ) {

                    var body = JSON.parse(data);
                    //override the out to match zipOut, as json files get written to options.out
                    options.out = unzippedFile;
                    saveMedia(options, body, done);

                  });

                }

              } else {

                done();

              }

            });

            unzipper.on("error", function(error) {
              grunt.log.error("An error occurred unzipping the file %j: %s", zipPath, error);
              done(false);
            });

            unzipper.extract({
              path: options.zipOut
            });
          } else {
            done(false);
          }

        }).pipe(fs.createWriteStream(zipPath));

      });

    }

    function saveMedia(options, body, done) {

      var mediaAssets = getMediaAssets( body, options.mediaCwd );
      var client = makeClient( options.aws );

      grunt.verbose.writeln("Media queue is:");
      mediaAssets.forEach(function (p) {
        grunt.verbose.writeln("  %j", p);
      });

      var loadCounter = 0;
      var next = function() {
        loadCounter--;
        fillQueue();
      };

      var fillQueue = function() {
        if (mediaAssets.length === 0 && loadCounter === 0) {
          writeJsonFile( options.out, body );
          done();
        } else {
          while (mediaAssets.length > 0 && loadCounter < options.maxConnections) {
            loadCounter++;
            verifyDownload( client, mediaAssets.shift(), options.mediaOut, next );
          }
        }
      };

      fillQueue();
    }

    function verifyDownload( client, remotePath, mediaOut, doneCallback ) {

      var localPath = path.join(mediaOut, remotePath);
      var localHash = null;

      grunt.verbose.writeln("Verifying %j -> %j", remotePath, localPath);
      fs.readFile( localPath, function ( err, data ) {
        if (err) {
          grunt.verbose.error("Etag calculation of local file failed: %s", err);
        } else {
          localHash = crypto.createHash('md5').update(data).digest('hex');
        }

        createPath(path.dirname(localPath), function (error) {
          if (!error) {
            downloadFile(client, remotePath, localPath, localHash, doneCallback);
          }
        });
      });

    }

    function writeJsonFile(out, body) {
      grunt.log.subhead( "Retrieving content..." );
      grunt.log.write( out + " ");
      grunt.log.ok( "saved" );
      grunt.file.write(out, JSON.stringify(body, null, '\t'));

    }

    function downloadFile(client, src, dest, etag, doneCallback) {
      var requestHeaders = { };

      grunt.verbose.writeln("S3 GET %j", src);

      if (etag) {
        grunt.verbose.writeln("If-None-Match: %s", etag);
        requestHeaders["If-None-Match"] = etag;
      }

      client.getFile(src, requestHeaders, function (err, res) {
        if (responseOk(src, err, res, HTTP_NOT_MODIFIED)) {
          var file = fs.createWriteStream(dest);
          file.on("error", function(e) {
            logError("Error writing: %s", e);
            doneCallback();
          });

          res
            .on('error', function (err) {
              logError("Error reading %j: %s", src, err);
              doneCallback();
            })
            .on('end', function () {
              logOk( "downloaded" );
              doneCallback();
            });

          res.pipe(file);
        } else {
          doneCallback();
        }
      });

    }

    function requestFiles(options, gruntCallback) {
      grunt.log.subhead( "Retrieving files..." );
      var url = createApiUrl(options, createRequestId());
      grunt.verbose.writeln("Url is %j", url);

      if (isZipQuery(options.query)) {
        grunt.verbose.writeln("Zip job");
        requestZip(url, options, gruntCallback);
      } else {
        grunt.verbose.writeln("JSON job");
        requestJson(url, options, gruntCallback);
      }
    }

    function isZipQuery(query) {
      return query.indexOf("dump/zip/") === 0;
    }

    function normalizeDir(path) {
      // TODO: change path string operations to use path lib, and make this
      // function unnecessary
      if (path == null) {
        return null;
      }
      path = String(path);
      if (path === "") {
        return "./";
      }
      if (path.slice(-1) !== "/") {
        return path + "/";
      }
      return path;
    }

    function getOptions() {
      // Mix in default options, .shampoorc file
      var options = rc("shampoo", thisTask.options({
        api: 1,
        query: "dump/json/single-file",
        out: "data/content.json",
        mediaOut: null,
        mediaCwd: null,
        maxConnections: DEFAULT_MAX_CONNECTIONS
      }));

      var messages = [ ];
      var missing = { };
      var required = [ "key", "secret", "domain", "query", "out" ];

      if (isZipQuery(options.query)) {
        required.push("zipOut");
      }

      required.forEach(function (optionName) {
        if (!options[optionName]) {
          missing[optionName] = true;
        }
      });

      var missingArray = Object.keys(missing);
      if (missingArray.length > 0) {
        messages.push("The following required options are not set: " +
          missingArray.join(", "));
      }

      if (missing.key || missing.secret) {
        messages.push("Values for 'key' and 'secret' are found in your Shampoo account under Settings.");
      }

      if (missing.zipOut) {
        messages.push(util.format(
          "The query %j returns a zip file. This requires the 'zipOut' option to be set.",
          options.query
        ));
      }

      options.mediaOut = normalizeDir(options.mediaOut);
      if (options.mediaCwd == null) {
        options.mediaCwd = options.mediaOut;
      } else {
        options.mediaCwd = normalizeDir(options.mediaCwd);
      }

      var parsedMaxConnections = parseInt(options.maxConnections, 10);
      if (isNaN(options.maxConnections)) {
        messages.push(util.format(
          "Invalid value for maxConnections: %j. Assuming default of %d.",
          options.maxConnections, DEFAULT_MAX_CONNECTIONS
        ));
        parsedMaxConnections = DEFAULT_MAX_CONNECTIONS;
      } else if (parsedMaxConnections < 1) {
        messages.push(
          "Value for maxConnections must be 1 or greater. Assuming 1.");
        parsedMaxConnections = 1;
      }

      options.maxConnections = parsedMaxConnections;

      return {
        options: options,
        messages: messages,
        ok: messages.length === 0
      };
    }

    function createRequestId() {
      return Date.now().toString(36) +
        (Math.random() * 9007199254740992).toString(36);
    }

    function createToken(secret, key, requestId) {
      return sha256("" + secret + key + requestId);
    }

    function createApiUrl(options, requestId) {
      var url = [
          options.https ? "https" : "http",
          "://",
          options.domain,
          "/api/v",
          options.api,
          "/",
          options.query
        ].join("");

      var queryParams = _.merge({
          requestId: requestId,
          token: createToken(options.secret, options.key, requestId)
        }, options.params || {});

      return url + "?" + querystring.stringify(queryParams);
    }

    function main() {
      var optionResult = getOptions();
      var messagesString = optionResult.messages.join("\n");
      var done = thisTask.async();

      if (optionResult.ok) {
        grunt.log.writeln(messagesString);
        requestFiles(optionResult.options, done);
      } else {
        grunt.log.error(messagesString);
        done(false);
      }

    }

    return main();
  });
};
<|endoftext|>


<commit_before>/** @jsx dom */
import dom from 'magic-virtual-element';
import * as Field from '../field';

export const propTypes = {
	autocomplete: {
		type: 'boolean'
	},
	checked: {
		type: 'boolean'
	},
	class: {
		type: 'string'
	},
	disabled: {
		type: 'boolean'
	},
	error: {
		type: 'string'
	},
	hint: {
		type: 'string'
	},
	id: {
		type: 'string'
	},
	label: {
		type: 'string'
	},
	max: {
		type: 'number'
	},
	maxLength: {
		type: 'number'
	},
	min: {
		type: 'number'
	},
	minLength: {
		type: 'number'
	},
	name: {
		type: 'string'
	},
	onChange: {
		type: 'function'
	},
	onInput: {
		type: 'function'
	},
	pattern: {
		type: 'string'
	},
	placeholder: {
		type: 'string'
	},
	readonly: {
		type: 'boolean'
	},
	required: {
		type: 'boolean'
	},
	size: {
		type: 'number'
	},
	type: {
		type: 'string'
	},
	validate: {
		type: 'boolean'
	},
	validationMessage: {
		type: 'function'
	},
	value: {
		type: 'string'
	}
};

export const defaultProps = {
	type: 'text',
	validationMessage(valid, el) {
		return el.validationMessage;
	}
};

export function render({props, state}, setState) {
	const {checked, disabled, name, placeholder, readonly, size, type, value} = props;
	const {hint, id, label} = props;
	const {max, maxLength, min, minLength, pattern, required, step} = props;
	const {onChange, onInput} = props;
	const error = props.error || state.error;
	const validate = props.validate || state.validate;
	const fieldAttrs = {error, hint, id, label};
	const inputAttrs = {
		autocomplete, checked, disabled, id, name, placeholder, readonly, size, type,
		max, maxLength, min, minLength, pattern, required, step,
		value: String(value || '')
	};

	function checkError(e) {
		const el = e.target;
		const validity = el.validity;
		setState({error: props.validationMessage(validity, el)});
	}

	function handleInput(e) {
		if (onInput) {
			onInput(e);
		}

		if (validate) {
			checkError(e);
		}
	}

	function handleChange(e) {
		if (onChange) {
			onChange(e);
		}

		if (validate) {
			checkError(e);
		}
	}

	function handleInvalid(e) {
		setState({validate: true});
		checkError(e);
	}

	return (
		<Field class={['InputField', props.class]} {...fieldAttrs}>
			<input {...inputAttrs} onChange={handleChange} onInput={handleInput} onInvalid={handleInvalid}/>
		</Field>
	);
}

export function afterRender({props}, el) {
	const input = el.querySelector('input');
	input.setCustomValidity(props.error || '');
}
<commit_msg>Fix `autocomplete` being `undefined`<commit_after>/** @jsx dom */
import dom from 'magic-virtual-element';
import * as Field from '../field';

export const propTypes = {
	autocomplete: {
		type: 'boolean'
	},
	checked: {
		type: 'boolean'
	},
	class: {
		type: 'string'
	},
	disabled: {
		type: 'boolean'
	},
	error: {
		type: 'string'
	},
	hint: {
		type: 'string'
	},
	id: {
		type: 'string'
	},
	label: {
		type: 'string'
	},
	max: {
		type: 'number'
	},
	maxLength: {
		type: 'number'
	},
	min: {
		type: 'number'
	},
	minLength: {
		type: 'number'
	},
	name: {
		type: 'string'
	},
	onChange: {
		type: 'function'
	},
	onInput: {
		type: 'function'
	},
	pattern: {
		type: 'string'
	},
	placeholder: {
		type: 'string'
	},
	readonly: {
		type: 'boolean'
	},
	required: {
		type: 'boolean'
	},
	size: {
		type: 'number'
	},
	type: {
		type: 'string'
	},
	validate: {
		type: 'boolean'
	},
	validationMessage: {
		type: 'function'
	},
	value: {
		type: 'string'
	}
};

export const defaultProps = {
	type: 'text',
	validationMessage(valid, el) {
		return el.validationMessage;
	}
};

export function render({props, state}, setState) {
	const {autocomplete, checked, disabled, name, placeholder, readonly, size, type, value} = props;
	const {hint, id, label} = props;
	const {max, maxLength, min, minLength, pattern, required, step} = props;
	const {onChange, onInput} = props;
	const error = props.error || state.error;
	const validate = props.validate || state.validate;
	const fieldAttrs = {error, hint, id, label};
	const inputAttrs = {
		autocomplete, checked, disabled, id, name, placeholder, readonly, size, type,
		max, maxLength, min, minLength, pattern, required, step,
		value: String(value || '')
	};

	function checkError(e) {
		const el = e.target;
		const validity = el.validity;
		setState({error: props.validationMessage(validity, el)});
	}

	function handleInput(e) {
		if (onInput) {
			onInput(e);
		}

		if (validate) {
			checkError(e);
		}
	}

	function handleChange(e) {
		if (onChange) {
			onChange(e);
		}

		if (validate) {
			checkError(e);
		}
	}

	function handleInvalid(e) {
		setState({validate: true});
		checkError(e);
	}

	return (
		<Field class={['InputField', props.class]} {...fieldAttrs}>
			<input {...inputAttrs} onChange={handleChange} onInput={handleInput} onInvalid={handleInvalid}/>
		</Field>
	);
}

export function afterRender({props}, el) {
	const input = el.querySelector('input');
	input.setCustomValidity(props.error || '');
}
<|endoftext|>


<commit_before>/*
 * grunt-vrunner
 * http://vrest.io
 *
 * Copyright (c) 2015 vREST Team
 * Licensed under the MIT license.
 */

'use strict';

var vrunner = require('vrunner'), chalk = require('chalk');

module.exports = function(grunt) {

  grunt.registerTask('vrunner', 'Runs vREST test cases.', function() {
    var done = this.async();
    var over = function(err,dontExit){
      if(!err) err = 'An unknown glitch found.';
      if(!Array.isArray(err)) err = [err];
      err.forEach(function(error){
        console.log(error);
      });
      if(!dontExit) done();
    };
    var options = this.options();
    var Runner = (new vrunner(options));
    Runner.run(function(err,report,remarks){
      if(err) over(err);
      else {
        grunt.log.ok('EXECUTION OF ALL TEST CASES SUCCESSFULLY COMPLETED.');
        console.log(remarks,report);
        done();
      }
    });
    Runner.on('testcase',function(pass,tc,trtc){
      if(pass){
        grunt.log.writeln(tc.method+' --> '+tc.url+' --> '+chalk.green('PASSED'));
      } else if(pass === false){
        grunt.log.writeln(tc.method+' --> '+tc.url+' --> '+chalk.red.bold('FAILED'));
      } else {
        grunt.log.writeln(tc.method+' --> '+tc.url+' --> '+chalk.cyan('NOT_EXECUTED'));
      }
    });
    Runner.on('error',function(err){
      grunt.log.error();
      over(err);
    });
    Runner.on('warning',function(warning){
      console.log(chalk.yellow('WARNING'));
      over(warning,true);
    });
  });
};
<commit_msg>display improvements done<commit_after>/*
 * grunt-vrunner
 * http://vrest.io
 *
 * Copyright (c) 2015 vREST Team
 * Licensed under the MIT license.
 */

'use strict';

var vrunner = require('vrunner'), chalk = require('chalk');

module.exports = function(grunt) {

  //add right side padding
  var rpad = function(str, totalSize, padChar){
    if(!padChar) padChar = ' ';
    if(str.length >= totalSize) return str;
    else {
      for(var i = str.length; i < totalSize; i++){
        str += padChar;
      }
      return str;
    }
  };

  var getMethodName = function(method){
    if(method === "GET") return chalk.blue.bold(method) + '    ';
    else if(method === "POST") return chalk.bold(method) + '   ';
    else if(method === "PUT") return chalk.green.bold(method) + '    ';
    else if(method === "PATCH") return chalk.magenta.bold(method) + '  ';
    else if(method === "DELETE") return chalk.red.bold(method) + ' ';
    else return chalk.bold(method) + ' ';
  };

  grunt.registerTask('vrunner', 'Runs vREST test cases.', function() {
    var done = this.async();
    var over = function(err,dontExit){
      if(!err) err = 'An unknown glitch found.';
      if(!Array.isArray(err)) err = [err];
      err.forEach(function(error){
        console.log(error);
      });
      if(!dontExit) done();
    };
    var options = this.options();
    var Runner = (new vrunner(options));
    Runner.run(function(err,report,remarks){
      if(err) over(err);
      else {
        //grunt.log.ok('EXECUTION OF ALL TEST CASES SUCCESSFULLY COMPLETED.');
        console.log(remarks,report);
        done();
      }
    });

    var index = 1;
    Runner.on('testcase',function(pass,tc,trtc){
      //console.log(trtc.);
      var prefix = rpad(index + '.', 5) + getMethodName(tc.method);
      index++;
      if(pass){
        grunt.log.writeln(prefix + chalk.green.bold(tc.summary || tc.url) + ' (' + trtc.executionTime + 'ms) ');
      } else if(pass === false){
        grunt.log.writeln(prefix + chalk.red.bold(tc.summary || tc.url) + ' (' + trtc.executionTime + 'ms) ');
      } else {
        grunt.log.writeln(prefix + chalk.cyan.bold('[Not Executed] ' + (tc.summary || tc.url)) + ' (' + trtc.executionTime + 'ms) ');
      }
    });

    Runner.on('error',function(err){
      grunt.log.error();
      over(err);
    });

    Runner.on('log', function(message, level){
      if(!level) level = 'info';
      message = '>> ' + message;
      if(level === 'error') message = chalk.red.bold(message);
      else message = chalk.blue.bold(message);
      console.log(message);
    });

    Runner.on('warning',function(warning){
      //console.log(chalk.yellow('WARNING'));
      //over(warning,true);
    });
  });
};
<|endoftext|>