mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-09 18:37:50 +00:00
Remove build from this repo to move to lodash-cli.
Former-commit-id: 0f9e802dd744a97494a10537442a28aae40dc72a
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,5 +6,3 @@
|
|||||||
*.map
|
*.map
|
||||||
modularize
|
modularize
|
||||||
node_modules
|
node_modules
|
||||||
vendor/closure-compiler
|
|
||||||
vendor/uglifyjs
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ lodash.js
|
|||||||
index.js
|
index.js
|
||||||
bower.json
|
bower.json
|
||||||
component.json
|
component.json
|
||||||
build
|
|
||||||
doc
|
doc
|
||||||
modularize
|
modularize
|
||||||
node_modules
|
node_modules
|
||||||
|
|||||||
@@ -8,15 +8,12 @@ env:
|
|||||||
- TEST_COMMAND="phantomjs ./test/test.js ../dist/lodash.compat.min.js"
|
- TEST_COMMAND="phantomjs ./test/test.js ../dist/lodash.compat.min.js"
|
||||||
- TEST_COMMAND="node ./test/test.js ../dist/lodash.js"
|
- TEST_COMMAND="node ./test/test.js ../dist/lodash.js"
|
||||||
- TEST_COMMAND="node ./test/test.js ../dist/lodash.min.js"
|
- TEST_COMMAND="node ./test/test.js ../dist/lodash.min.js"
|
||||||
- TEST_COMMAND="node ./test/test-build.js --time-limit 48m"
|
|
||||||
git:
|
git:
|
||||||
depth: 1
|
depth: 1
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
before_script:
|
before_script:
|
||||||
- "tar -xzvf vendor/closure-compiler.tar.gz -C vendor"
|
|
||||||
- "tar -xzvf vendor/uglifyjs.tar.gz -C vendor"
|
|
||||||
- "npm install -g istanbul"
|
- "npm install -g istanbul"
|
||||||
script:
|
script:
|
||||||
$TEST_COMMAND
|
$TEST_COMMAND
|
||||||
|
|||||||
@@ -11,11 +11,9 @@
|
|||||||
"*.map",
|
"*.map",
|
||||||
"*.md",
|
"*.md",
|
||||||
"*.txt",
|
"*.txt",
|
||||||
"build.js",
|
|
||||||
"index.js",
|
"index.js",
|
||||||
"component.json",
|
"component.json",
|
||||||
"package.json",
|
"package.json",
|
||||||
"build",
|
|
||||||
"doc",
|
"doc",
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"perf",
|
"perf",
|
||||||
|
|||||||
793
build/minify.js
793
build/minify.js
@@ -1,793 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
;(function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/** Load Node.js modules */
|
|
||||||
var cp = require('child_process'),
|
|
||||||
https = require('https'),
|
|
||||||
zlib = require('zlib');
|
|
||||||
|
|
||||||
/** Load other modules */
|
|
||||||
var _ = require('../lodash.js'),
|
|
||||||
preprocess = require('./pre-compile.js'),
|
|
||||||
postprocess = require('./post-compile.js'),
|
|
||||||
tar = require('../vendor/tar/tar.js'),
|
|
||||||
util = require('./util.js');
|
|
||||||
|
|
||||||
/** Module shortcuts */
|
|
||||||
var fs = util.fs,
|
|
||||||
path = util.path;
|
|
||||||
|
|
||||||
/** The Git object ID of `closure-compiler.tar.gz` */
|
|
||||||
var closureId = '9fd5d61c1b706e7505aeb5187941c2c5497e5fd8';
|
|
||||||
|
|
||||||
/** The Git object ID of `uglifyjs.tar.gz` */
|
|
||||||
var uglifyId = '7de2795a3af58d1b293e3b0e83cdbc994f4941dc';
|
|
||||||
|
|
||||||
/** The path of the directory that is the base of the repository */
|
|
||||||
var basePath = fs.realpathSync(path.join(__dirname, '..'));
|
|
||||||
|
|
||||||
/** The path of the `vendor` directory */
|
|
||||||
var vendorPath = path.join(basePath, 'vendor');
|
|
||||||
|
|
||||||
/** The path to the Closure Compiler `.jar` */
|
|
||||||
var closurePath = path.join(vendorPath, 'closure-compiler', 'compiler.jar');
|
|
||||||
|
|
||||||
/** The path to the UglifyJS module */
|
|
||||||
var uglifyPath = path.join(vendorPath, 'uglifyjs', 'tools', 'node.js');
|
|
||||||
|
|
||||||
/** The Closure Compiler command-line options */
|
|
||||||
var closureOptions = ['--warning_level=QUIET'];
|
|
||||||
|
|
||||||
/** The media type for raw blob data */
|
|
||||||
var mediaType = 'application/vnd.github.v3.raw';
|
|
||||||
|
|
||||||
/** Used to detect the Node.js executable in command-line arguments */
|
|
||||||
var reNode = RegExp('(?:^|' + path.sepEscaped + ')node(?:\\.exe)?$', 'i');
|
|
||||||
|
|
||||||
/** Used to reference parts of the blob href */
|
|
||||||
var location = (function() {
|
|
||||||
var host = 'api.github.com',
|
|
||||||
origin = 'https://api.github.com',
|
|
||||||
pathname = '/repos/bestiejs/lodash/git/blobs';
|
|
||||||
|
|
||||||
return {
|
|
||||||
'host': host,
|
|
||||||
'href': origin + pathname,
|
|
||||||
'origin': origin,
|
|
||||||
'pathname': pathname
|
|
||||||
};
|
|
||||||
}());
|
|
||||||
|
|
||||||
/** The Closure Compiler optimization modes */
|
|
||||||
var optimizationModes = {
|
|
||||||
'simple': 'SIMPLE_OPTIMIZATIONS',
|
|
||||||
'advanced': 'ADVANCED_OPTIMIZATIONS'
|
|
||||||
};
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minifies a given Lo-Dash `source` and invokes the `options.onComplete`
|
|
||||||
* callback when finished. The `onComplete` callback is invoked with one
|
|
||||||
* argument; (outputSource).
|
|
||||||
*
|
|
||||||
* @param {string|string[]} [source=''] The source to minify or array of commands.
|
|
||||||
* -o, --output - Write output to a given path/filename.
|
|
||||||
* -s, --silent - Skip status updates normally logged to the console.
|
|
||||||
* -t, --template - Applies template specific minifier options.
|
|
||||||
*
|
|
||||||
* @param {Object} [options={}] The options object.
|
|
||||||
* @param {string} [options.outputPath] Write output to a given path/filename.
|
|
||||||
* @param {boolean} [options.isSilent] Skip status updates normally logged to the console.
|
|
||||||
* @param {boolean} [options.isTemplate] Applies template specific minifier options.
|
|
||||||
* @param {Function} [options.onComplete] The function called once minification has finished.
|
|
||||||
*/
|
|
||||||
function minify(source, options) {
|
|
||||||
// used to specify the source map URL
|
|
||||||
var sourceMapURL;
|
|
||||||
|
|
||||||
// used to specify the default minifer modes
|
|
||||||
var modes = ['simple', 'advanced', 'hybrid'];
|
|
||||||
|
|
||||||
source || (source = '');
|
|
||||||
options || (options = {});
|
|
||||||
|
|
||||||
// juggle arguments
|
|
||||||
if (Array.isArray(source)) {
|
|
||||||
// convert commands to an options object
|
|
||||||
options = source;
|
|
||||||
|
|
||||||
// used to report invalid command-line arguments
|
|
||||||
var invalidArgs = _.reject(options.slice(reNode.test(options[0]) ? 2 : 0), function(value, index, options) {
|
|
||||||
if (/^(?:-o|--output)$/.test(options[index - 1]) ||
|
|
||||||
/^modes=.*$/.test(value)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
var result = [
|
|
||||||
'-o', '--output',
|
|
||||||
'-p', '--source-map',
|
|
||||||
'-s', '--silent',
|
|
||||||
'-t', '--template'
|
|
||||||
].indexOf(value) > -1;
|
|
||||||
|
|
||||||
if (!result && /^(?:-p|--source-map)$/.test(options[index - 1])) {
|
|
||||||
result = true;
|
|
||||||
sourceMapURL = value;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
|
|
||||||
// report invalid arguments
|
|
||||||
if (invalidArgs.length) {
|
|
||||||
console.log(
|
|
||||||
'\n' +
|
|
||||||
'Invalid argument' + (invalidArgs.length > 1 ? 's' : '') +
|
|
||||||
' passed: ' + invalidArgs.join(', ')
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var filePath = options[options.length - 1],
|
|
||||||
isMapped = _.contains(options, '-p') || _.contains(options, '--source-map'),
|
|
||||||
isSilent = _.contains(options, '-s') || _.contains(options, '--silent'),
|
|
||||||
isTemplate = _.contains(options, '-t') || _.contains(options, '--template'),
|
|
||||||
outputPath = path.join(path.dirname(filePath), path.basename(filePath, '.js') + '.min.js');
|
|
||||||
|
|
||||||
modes = options.reduce(function(result, value) {
|
|
||||||
var match = value.match(/modes=(.*)$/);
|
|
||||||
return match ? match[1].split(/, */) : result;
|
|
||||||
}, modes);
|
|
||||||
|
|
||||||
outputPath = options.reduce(function(result, value, index) {
|
|
||||||
if (/-o|--output/.test(value)) {
|
|
||||||
result = options[index + 1];
|
|
||||||
var dirname = path.dirname(result);
|
|
||||||
fs.mkdirpSync(dirname);
|
|
||||||
result = path.join(fs.realpathSync(dirname), path.basename(result));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}, outputPath);
|
|
||||||
|
|
||||||
options = {
|
|
||||||
'filePath': filePath,
|
|
||||||
'isMapped': isMapped,
|
|
||||||
'isSilent': isSilent,
|
|
||||||
'isTemplate': isTemplate,
|
|
||||||
'modes': modes,
|
|
||||||
'outputPath': outputPath,
|
|
||||||
'sourceMapURL': sourceMapURL
|
|
||||||
};
|
|
||||||
|
|
||||||
source = fs.readFileSync(filePath, 'utf8');
|
|
||||||
}
|
|
||||||
|
|
||||||
modes = options.modes || modes;
|
|
||||||
if (options.isMapped) {
|
|
||||||
modes = modes.filter(function(mode) {
|
|
||||||
return mode != 'hybrid';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (options.isTemplate) {
|
|
||||||
modes = modes.filter(function(mode) {
|
|
||||||
return mode != 'advanced';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
options.modes = modes;
|
|
||||||
|
|
||||||
// fetch the Closure Compiler
|
|
||||||
getDependency({
|
|
||||||
'id': 'closure-compiler',
|
|
||||||
'hashId': closureId,
|
|
||||||
'path': vendorPath,
|
|
||||||
'title': 'the Closure Compiler',
|
|
||||||
'onComplete': function(exception) {
|
|
||||||
var error = exception;
|
|
||||||
|
|
||||||
// fetch UglifyJS
|
|
||||||
getDependency({
|
|
||||||
'id': 'uglifyjs',
|
|
||||||
'hashId': uglifyId,
|
|
||||||
'title': 'UglifyJS',
|
|
||||||
'path': vendorPath,
|
|
||||||
'onComplete': function(exception) {
|
|
||||||
error || (error = exception);
|
|
||||||
if (!error) {
|
|
||||||
new Minify(source, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Minify constructor used to keep state of each `minify` invocation.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @constructor
|
|
||||||
* @param {string} source The source to minify.
|
|
||||||
* @param {Object} options The options object.
|
|
||||||
* outputPath - Write output to a given path/filename.
|
|
||||||
* isSilent - Skip status updates normally logged to the console.
|
|
||||||
* isTemplate - Applies template specific minifier options.
|
|
||||||
* onComplete - The function called once minification has finished.
|
|
||||||
*/
|
|
||||||
function Minify(source, options) {
|
|
||||||
// juggle arguments
|
|
||||||
if (typeof source == 'object' && source) {
|
|
||||||
options = source || options;
|
|
||||||
source = options.source || '';
|
|
||||||
}
|
|
||||||
this.compiled = { 'simple': {}, 'advanced': {} };
|
|
||||||
this.hybrid = { 'simple': {}, 'advanced': {} };
|
|
||||||
this.uglified = {};
|
|
||||||
|
|
||||||
this.filePath = options.filePath;
|
|
||||||
this.isMapped = !!options.isMapped;
|
|
||||||
this.isSilent = !!options.isSilent;
|
|
||||||
this.isTemplate = !!options.isTemplate;
|
|
||||||
this.outputPath = options.outputPath;
|
|
||||||
this.sourceMapURL = options.sourceMapURL;
|
|
||||||
|
|
||||||
var modes = this.modes = options.modes;
|
|
||||||
source = this.source = preprocess(source, options);
|
|
||||||
|
|
||||||
this.onComplete = options.onComplete || function(data) {
|
|
||||||
var outputPath = this.outputPath,
|
|
||||||
sourceMap = data.sourceMap;
|
|
||||||
|
|
||||||
fs.writeFileSync(outputPath, data.source, 'utf8');
|
|
||||||
if (sourceMap) {
|
|
||||||
fs.writeFileSync(getMapPath(outputPath), sourceMap, 'utf8');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// begin the minification process
|
|
||||||
if (_.contains(modes, 'simple')) {
|
|
||||||
closureCompile.call(this, source, 'simple', onClosureSimpleCompile.bind(this));
|
|
||||||
} else if (_.contains(modes, 'advanced')) {
|
|
||||||
onClosureSimpleGzip.call(this);
|
|
||||||
} else {
|
|
||||||
onClosureAdvancedGzip.call(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches a required `.tar.gz` dependency with the given Git object ID from
|
|
||||||
* the Lo-Dash repo on GitHub. The object ID may be obtained by running
|
|
||||||
* `git hash-object path/to/dependency.tar.gz`.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} options The options object.
|
|
||||||
* id - The Git object ID of the `.tar.gz` file.
|
|
||||||
* onComplete - The function called once the extraction has finished.
|
|
||||||
* path - The path of the extraction directory.
|
|
||||||
* title - The dependency's title used in status updates logged to the console.
|
|
||||||
*/
|
|
||||||
function getDependency(options) {
|
|
||||||
options || (options = {});
|
|
||||||
|
|
||||||
var ran,
|
|
||||||
destPath = options.path,
|
|
||||||
hashId = options.hashId,
|
|
||||||
id = options.id,
|
|
||||||
onComplete = options.onComplete,
|
|
||||||
title = options.title;
|
|
||||||
|
|
||||||
// exit early if dependency exists
|
|
||||||
if (fs.existsSync(path.join(destPath, id))) {
|
|
||||||
onComplete();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var callback = function(exception) {
|
|
||||||
if (ran) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (exception) {
|
|
||||||
console.error([
|
|
||||||
'There was a problem installing ' + title + '.',
|
|
||||||
'Try running the command as root, via `sudo`, or manually install by running:',
|
|
||||||
'',
|
|
||||||
"curl -H 'Accept: " + mediaType + "' " + location.href + '/' + hashId + " | tar xvz -C '" + destPath + "'",
|
|
||||||
''
|
|
||||||
].join('\n'));
|
|
||||||
}
|
|
||||||
ran = true;
|
|
||||||
process.removeListener('uncaughtException', callback);
|
|
||||||
onComplete(exception);
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('Downloading ' + title + '...');
|
|
||||||
process.on('uncaughtException', callback);
|
|
||||||
|
|
||||||
https.get({
|
|
||||||
'host': location.host,
|
|
||||||
'path': location.pathname + '/' + hashId,
|
|
||||||
'headers': {
|
|
||||||
// By default, all GitHub blob API endpoints return a JSON document
|
|
||||||
// containing Base64-encoded blob data. Overriding the `Accept` header
|
|
||||||
// with the GitHub raw media type returns the blob data directly.
|
|
||||||
// See http://developer.github.com/v3/media/.
|
|
||||||
'Accept': mediaType,
|
|
||||||
// As of 2013-04-24, the GitHub API mandates the `User-Agent` header
|
|
||||||
// for all requests.
|
|
||||||
'User-Agent': 'Lo-Dash/' + _.VERSION
|
|
||||||
}
|
|
||||||
}, function(response) {
|
|
||||||
var decompressor = zlib.createUnzip(),
|
|
||||||
parser = new tar.Extract({ 'path': destPath });
|
|
||||||
|
|
||||||
parser.on('end', callback);
|
|
||||||
response.pipe(decompressor).pipe(parser);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the Java command-line options used for faster minification by
|
|
||||||
* the Closure Compiler, invoking the `callback` when finished. Subsequent
|
|
||||||
* calls will lazily return the previously retrieved options. The `callback`
|
|
||||||
* is invoked with one argument; (options).
|
|
||||||
*
|
|
||||||
* See https://code.google.com/p/closure-compiler/wiki/FAQ#What_are_the_recommended_Java_VM_command-line_options?.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Function} callback The function called once the options have been retrieved.
|
|
||||||
*/
|
|
||||||
function getJavaOptions(callback) {
|
|
||||||
var result = [];
|
|
||||||
cp.exec('java -version -client -d32', function(error) {
|
|
||||||
if (!error && process.platform != 'win32') {
|
|
||||||
result.push('-client', '-d32');
|
|
||||||
}
|
|
||||||
getJavaOptions = function(callback) {
|
|
||||||
_.defer(callback, result);
|
|
||||||
};
|
|
||||||
callback(result);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves the source map path from the given output path.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {string} outputPath The output path.
|
|
||||||
* @returns {string} Returns the source map path.
|
|
||||||
*/
|
|
||||||
function getMapPath(outputPath) {
|
|
||||||
return path.join(path.dirname(outputPath), path.basename(outputPath, '.js') + '.map');
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compresses a `source` string using the Closure Compiler. Yields the
|
|
||||||
* minified result, and any exceptions encountered, to a `callback` function.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {string} source The JavaScript source to minify.
|
|
||||||
* @param {string} mode The optimization mode.
|
|
||||||
* @param {Function} callback The function called once the process has completed.
|
|
||||||
*/
|
|
||||||
function closureCompile(source, mode, callback) {
|
|
||||||
var filePath = this.filePath,
|
|
||||||
isAdvanced = mode == 'advanced',
|
|
||||||
isMapped = this.isMapped,
|
|
||||||
isSilent = this.isSilent,
|
|
||||||
isTemplate = this.isTemplate,
|
|
||||||
options = closureOptions.slice(),
|
|
||||||
outputPath = this.outputPath,
|
|
||||||
mapPath = getMapPath(outputPath),
|
|
||||||
sourceMapURL = this.sourceMapURL || path.basename(mapPath);
|
|
||||||
|
|
||||||
// remove copyright header to make other modifications easier
|
|
||||||
var license = (/^(?:\s*\/\/.*\s*|\s*\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\s*)*/.exec(source) || [''])[0];
|
|
||||||
if (license) {
|
|
||||||
source = source.replace(license, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasIIFE = /^;?\(function[^{]+{/.test(source),
|
|
||||||
isStrict = hasIIFE && /^;?\(function[^{]+{\s*["']use strict["']/.test(source);
|
|
||||||
|
|
||||||
// to avoid stripping the IIFE, convert it to a function call
|
|
||||||
if (hasIIFE && isAdvanced) {
|
|
||||||
source = source
|
|
||||||
.replace(/\(function/, '__iife__$&')
|
|
||||||
.replace(/\(this\)\)([\s;]*(\n\/\/.+)?)$/, ', this)$1');
|
|
||||||
}
|
|
||||||
|
|
||||||
options.push('--compilation_level=' + optimizationModes[mode]);
|
|
||||||
if (isMapped) {
|
|
||||||
options.push('--create_source_map=' + mapPath, '--source_map_format=V3');
|
|
||||||
}
|
|
||||||
if (isTemplate) {
|
|
||||||
options.push('--charset=UTF-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
getJavaOptions(function(javaOptions) {
|
|
||||||
var compiler = cp.spawn('java', javaOptions.concat('-jar', closurePath, options));
|
|
||||||
if (!isSilent) {
|
|
||||||
console.log('Compressing ' + path.basename(outputPath, '.js') + ' using the Closure Compiler (' + mode + ')...');
|
|
||||||
}
|
|
||||||
|
|
||||||
var error = '';
|
|
||||||
compiler.stderr.on('data', function(data) {
|
|
||||||
error += data;
|
|
||||||
});
|
|
||||||
|
|
||||||
var output = '';
|
|
||||||
compiler.stdout.on('data', function(data) {
|
|
||||||
output += data;
|
|
||||||
});
|
|
||||||
|
|
||||||
compiler.on('exit', function(status) {
|
|
||||||
// `status` contains the process exit code
|
|
||||||
if (status) {
|
|
||||||
var exception = new Error(error);
|
|
||||||
exception.status = status;
|
|
||||||
}
|
|
||||||
// restore IIFE and move exposed vars inside the IIFE
|
|
||||||
if (hasIIFE && isAdvanced) {
|
|
||||||
output = output
|
|
||||||
.replace(/__iife__\(/, '(')
|
|
||||||
.replace(/,\s*this\)([\s;]*(\n\/\/.+)?)$/, '(this))$1')
|
|
||||||
.replace(/^((?:var (?:\w+=(?:!0|!1|null)[,;])+)?)([\s\S]*?function[^{]+{)/, '$2$1');
|
|
||||||
}
|
|
||||||
// inject "use strict" directive
|
|
||||||
if (isStrict) {
|
|
||||||
output = output.replace(/^[\s\S]*?function[^{]+{/, '$&"use strict";');
|
|
||||||
}
|
|
||||||
// restore copyright header
|
|
||||||
if (license) {
|
|
||||||
output = license + output;
|
|
||||||
}
|
|
||||||
if (isMapped) {
|
|
||||||
var mapOutput = fs.readFileSync(mapPath, 'utf8');
|
|
||||||
fs.unlinkSync(mapPath);
|
|
||||||
output = output.replace(/[\s;]*$/, '\n//# sourceMappingURL=' + sourceMapURL);
|
|
||||||
|
|
||||||
mapOutput = JSON.parse(mapOutput);
|
|
||||||
mapOutput.file = path.basename(outputPath);
|
|
||||||
mapOutput.sources = [path.basename(filePath)];
|
|
||||||
mapOutput = JSON.stringify(mapOutput, null, 2);
|
|
||||||
}
|
|
||||||
callback(exception, output, mapOutput);
|
|
||||||
});
|
|
||||||
|
|
||||||
// proxy the standard input to the Closure Compiler
|
|
||||||
compiler.stdin.end(source);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compresses a `source` string using UglifyJS. Yields the result to a
|
|
||||||
* `callback` function. This function is synchronous; the `callback` is used
|
|
||||||
* for symmetry.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {string} source The JavaScript source to minify.
|
|
||||||
* @param {string} label The label to log.
|
|
||||||
* @param {Function} callback The function called once the process has completed.
|
|
||||||
*/
|
|
||||||
function uglify(source, label, callback) {
|
|
||||||
if (!this.isSilent) {
|
|
||||||
console.log('Compressing ' + path.basename(this.outputPath, '.js') + ' using ' + label + '...');
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
var uglifyJS = require(uglifyPath);
|
|
||||||
|
|
||||||
// 1. parse
|
|
||||||
var toplevel = uglifyJS.parse(source);
|
|
||||||
|
|
||||||
// 2. compress
|
|
||||||
// enable unsafe comparisons
|
|
||||||
toplevel.figure_out_scope();
|
|
||||||
toplevel = toplevel.transform(uglifyJS.Compressor({
|
|
||||||
'comparisons': false,
|
|
||||||
'unsafe': true,
|
|
||||||
'unsafe_comps': true,
|
|
||||||
'warnings': false
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 3. mangle
|
|
||||||
// excluding the `define` function exposed by AMD loaders
|
|
||||||
toplevel.figure_out_scope();
|
|
||||||
toplevel.compute_char_frequency();
|
|
||||||
toplevel.mangle_names({
|
|
||||||
'except': ['define']
|
|
||||||
});
|
|
||||||
|
|
||||||
// 4. output
|
|
||||||
// restrict lines to 500 characters for consistency with the Closure Compiler
|
|
||||||
var stream = uglifyJS.OutputStream({
|
|
||||||
'ascii_only': !this.isTemplate,
|
|
||||||
'comments': /^!|@cc_on|@license|@preserve/i,
|
|
||||||
'max_line_len': 500,
|
|
||||||
});
|
|
||||||
|
|
||||||
toplevel.print(stream);
|
|
||||||
}
|
|
||||||
catch(e) {
|
|
||||||
var exception = e;
|
|
||||||
}
|
|
||||||
callback(exception, stream && String(stream));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Closure Compiler callback for simple optimizations.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} [exception] The error object.
|
|
||||||
* @param {string} result The resulting minified source.
|
|
||||||
* @param {string} map The source map output.
|
|
||||||
*/
|
|
||||||
function onClosureSimpleCompile(exception, result, map) {
|
|
||||||
if (exception) {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
result = postprocess(result);
|
|
||||||
|
|
||||||
var simple = this.compiled.simple;
|
|
||||||
simple.source = result;
|
|
||||||
simple.sourceMap = map;
|
|
||||||
zlib.gzip(result, onClosureSimpleGzip.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Closure Compiler `gzip` callback for simple optimizations.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} [exception] The error object.
|
|
||||||
* @param {Buffer} result The resulting gzipped source.
|
|
||||||
*/
|
|
||||||
function onClosureSimpleGzip(exception, result) {
|
|
||||||
if (exception) {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
if (result != null) {
|
|
||||||
if (!this.isSilent) {
|
|
||||||
console.log('Done. Size: %d bytes.', result.length);
|
|
||||||
}
|
|
||||||
this.compiled.simple.gzip = result;
|
|
||||||
}
|
|
||||||
// compile the source using advanced optimizations
|
|
||||||
if (_.contains(this.modes, 'advanced')) {
|
|
||||||
closureCompile.call(this, this.source, 'advanced', onClosureAdvancedCompile.bind(this));
|
|
||||||
} else {
|
|
||||||
onClosureAdvancedGzip.call(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Closure Compiler callback for advanced optimizations.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} [exception] The error object.
|
|
||||||
* @param {string} result The resulting minified source.
|
|
||||||
* @param {string} map The source map output.
|
|
||||||
*/
|
|
||||||
function onClosureAdvancedCompile(exception, result, map) {
|
|
||||||
if (exception) {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
result = postprocess(result);
|
|
||||||
|
|
||||||
var advanced = this.compiled.advanced;
|
|
||||||
advanced.source = result;
|
|
||||||
advanced.sourceMap = map;
|
|
||||||
zlib.gzip(result, onClosureAdvancedGzip.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Closure Compiler `gzip` callback for advanced optimizations.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} [exception] The error object.
|
|
||||||
* @param {Buffer} result The resulting gzipped source.
|
|
||||||
*/
|
|
||||||
function onClosureAdvancedGzip(exception, result) {
|
|
||||||
if (exception) {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
if (result != null) {
|
|
||||||
if (!this.isSilent) {
|
|
||||||
console.log('Done. Size: %d bytes.', result.length);
|
|
||||||
}
|
|
||||||
this.compiled.advanced.gzip = result;
|
|
||||||
}
|
|
||||||
// minify the source using UglifyJS
|
|
||||||
if (!this.isMapped) {
|
|
||||||
uglify.call(this, this.source, 'UglifyJS', onUglify.bind(this));
|
|
||||||
} else {
|
|
||||||
onComplete.call(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The UglifyJS callback.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} [exception] The error object.
|
|
||||||
* @param {string} result The resulting minified source.
|
|
||||||
*/
|
|
||||||
function onUglify(exception, result) {
|
|
||||||
if (exception) {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
result = postprocess(result);
|
|
||||||
this.uglified.source = result;
|
|
||||||
zlib.gzip(result, onUglifyGzip.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The UglifyJS `gzip` callback.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} [exception] The error object.
|
|
||||||
* @param {Buffer} result The resulting gzipped source.
|
|
||||||
*/
|
|
||||||
function onUglifyGzip(exception, result) {
|
|
||||||
if (exception) {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
if (result != null) {
|
|
||||||
if (!this.isSilent) {
|
|
||||||
console.log('Done. Size: %d bytes.', result.length);
|
|
||||||
}
|
|
||||||
this.uglified.gzip = result;
|
|
||||||
}
|
|
||||||
// minify the already Closure Compiler simple optimized source using UglifyJS
|
|
||||||
var modes = this.modes;
|
|
||||||
if (_.contains(modes, 'hybrid')) {
|
|
||||||
if (_.contains(modes, 'simple')) {
|
|
||||||
uglify.call(this, this.compiled.simple.source, 'hybrid (simple)', onSimpleHybrid.bind(this));
|
|
||||||
} else if (_.contains(modes, 'advanced')) {
|
|
||||||
onSimpleHybridGzip.call(this);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
onComplete.call(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The hybrid callback for simple optimizations.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} [exception] The error object.
|
|
||||||
* @param {string} result The resulting minified source.
|
|
||||||
*/
|
|
||||||
function onSimpleHybrid(exception, result) {
|
|
||||||
if (exception) {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
result = postprocess(result);
|
|
||||||
this.hybrid.simple.source = result;
|
|
||||||
zlib.gzip(result, onSimpleHybridGzip.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The hybrid `gzip` callback for simple optimizations.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} [exception] The error object.
|
|
||||||
* @param {Buffer} result The resulting gzipped source.
|
|
||||||
*/
|
|
||||||
function onSimpleHybridGzip(exception, result) {
|
|
||||||
if (exception) {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
if (result != null) {
|
|
||||||
if (!this.isSilent) {
|
|
||||||
console.log('Done. Size: %d bytes.', result.length);
|
|
||||||
}
|
|
||||||
this.hybrid.simple.gzip = result;
|
|
||||||
}
|
|
||||||
// minify the already Closure Compiler advance optimized source using UglifyJS
|
|
||||||
if (_.contains(this.modes, 'advanced')) {
|
|
||||||
uglify.call(this, this.compiled.advanced.source, 'hybrid (advanced)', onAdvancedHybrid.bind(this));
|
|
||||||
} else {
|
|
||||||
onComplete.call(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The hybrid callback for advanced optimizations.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} [exception] The error object.
|
|
||||||
* @param {string} result The resulting minified source.
|
|
||||||
*/
|
|
||||||
function onAdvancedHybrid(exception, result) {
|
|
||||||
if (exception) {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
result = postprocess(result);
|
|
||||||
this.hybrid.advanced.source = result;
|
|
||||||
zlib.gzip(result, onAdvancedHybridGzip.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The hybrid `gzip` callback for advanced optimizations.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} [exception] The error object.
|
|
||||||
* @param {Buffer} result The resulting gzipped source.
|
|
||||||
*/
|
|
||||||
function onAdvancedHybridGzip(exception, result) {
|
|
||||||
if (exception) {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
if (result != null) {
|
|
||||||
if (!this.isSilent) {
|
|
||||||
console.log('Done. Size: %d bytes.', result.length);
|
|
||||||
}
|
|
||||||
this.hybrid.advanced.gzip = result;
|
|
||||||
}
|
|
||||||
// finish by choosing the smallest compressed file
|
|
||||||
onComplete.call(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The callback executed after the source is minified and gzipped.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
function onComplete() {
|
|
||||||
var compiledSimple = this.compiled.simple,
|
|
||||||
compiledAdvanced = this.compiled.advanced,
|
|
||||||
uglified = this.uglified,
|
|
||||||
hybridSimple = this.hybrid.simple,
|
|
||||||
hybridAdvanced = this.hybrid.advanced;
|
|
||||||
|
|
||||||
var objects = [
|
|
||||||
compiledSimple,
|
|
||||||
compiledAdvanced,
|
|
||||||
uglified,
|
|
||||||
hybridSimple,
|
|
||||||
hybridAdvanced
|
|
||||||
];
|
|
||||||
|
|
||||||
var gzips = objects
|
|
||||||
.map(function(data) { return data.gzip; })
|
|
||||||
.filter(Boolean);
|
|
||||||
|
|
||||||
// select the smallest gzipped file and use its minified counterpart as the
|
|
||||||
// official minified release (ties go to the Closure Compiler)
|
|
||||||
var min = gzips.reduce(function(min, gzip) {
|
|
||||||
var length = gzip.length;
|
|
||||||
return min > length ? length : min;
|
|
||||||
}, Infinity);
|
|
||||||
|
|
||||||
// pass the minified source to the "onComplete" callback
|
|
||||||
objects.some(function(data) {
|
|
||||||
var gzip = data.gzip;
|
|
||||||
if (gzip && gzip.length == min) {
|
|
||||||
data.outputPath = this.outputPath;
|
|
||||||
this.onComplete(data);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
// expose `minify`
|
|
||||||
if (module != require.main) {
|
|
||||||
module.exports = minify;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// read the Lo-Dash source file from the first argument if the script
|
|
||||||
// was invoked directly (e.g. `node minify.js source.js`) and write to
|
|
||||||
// `<filename>.min.js`
|
|
||||||
(function() {
|
|
||||||
var options = process.argv;
|
|
||||||
if (options.length < 3) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
minify(options);
|
|
||||||
}());
|
|
||||||
}
|
|
||||||
}());
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
;(function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/** Load Node.js modules */
|
|
||||||
var fs = require('fs'),
|
|
||||||
vm = require('vm');
|
|
||||||
|
|
||||||
/** The minimal license/copyright template */
|
|
||||||
var licenseTemplate = [
|
|
||||||
'/**',
|
|
||||||
' * @license',
|
|
||||||
' * Lo-Dash <%= VERSION %> lodash.com/license | Underscore.js 1.5.1 underscorejs.org/LICENSE',
|
|
||||||
' */'
|
|
||||||
].join('\n');
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Post-process a given minified Lo-Dash `source`, preparing it for
|
|
||||||
* deployment.
|
|
||||||
*
|
|
||||||
* @param {string} source The source to process.
|
|
||||||
* @returns {string} Returns the processed source.
|
|
||||||
*/
|
|
||||||
function postprocess(source) {
|
|
||||||
// correct overly aggressive Closure Compiler advanced optimization
|
|
||||||
source = source
|
|
||||||
.replace(/(document[^&]+&&)\s*(?:\w+|!\d)/, '$1!({toString:0}+"")')
|
|
||||||
.replace(/"\t"/g, '"\\t"')
|
|
||||||
.replace(/"[^"]*?\\f[^"]*?"/g,
|
|
||||||
'" \\t\\x0B\\f\\xa0\\ufeff' +
|
|
||||||
'\\n\\r\\u2028\\u2029' +
|
|
||||||
'\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000"'
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
var context = vm.createContext({});
|
|
||||||
vm.runInContext(source, context);
|
|
||||||
} catch(e) { }
|
|
||||||
|
|
||||||
['forEach', 'forIn', 'forOwn'].forEach(function(methodName) {
|
|
||||||
var pairs = /[!=]==\s*([a-zA-Z]+)(?!\()|([a-zA-Z]+)\s*[!=]==/.exec((context._ || {})[methodName]),
|
|
||||||
varName = pairs && (pairs[1] || pairs[2]),
|
|
||||||
value = (value = varName && RegExp('\\b' + varName + '\\s*=\\s*!([01])\\b').exec(source)) && !+value[1];
|
|
||||||
|
|
||||||
if (typeof value == 'boolean') {
|
|
||||||
// replace vars for `false` and `true` with boolean literals
|
|
||||||
source = source.replace(RegExp('([!=]==\\s*)' + varName + '\\b(?!\\()|\\b' + varName + '(\\s*[!=]==)', 'g'), function(match, prelude, postlude, at) {
|
|
||||||
// avoid replacing local variables with the same name
|
|
||||||
return RegExp('\\b' + varName + '\\s*(?:,|=[^=])').test(source.slice(at - 10, at))
|
|
||||||
? match
|
|
||||||
: (prelude || '') + value + (postlude || '');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// replace `!1` and `!0` in expressions with `false` and `true` values
|
|
||||||
[/([!=]==)\s*!1\b|(.)!1\s*([!=]==)/g, /([!=]==)\s*!0\b|(.)!0\s*([!=]==)/g].forEach(function(regexp, index) {
|
|
||||||
source = source.replace(regexp, function(match, prelude, chr, postlude) {
|
|
||||||
return (prelude || chr + (/\w/.test(chr) ? ' ' : '')) + !!index + (postlude || '');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// flip `typeof` expressions to help optimize Safari and
|
|
||||||
// correct the AMD module definition for AMD build optimizers
|
|
||||||
// (e.g. from `"number" == typeof x` to `typeof x == "number")
|
|
||||||
source = source.replace(/(\w)?("[^"]+")\s*([!=]=)\s*(typeof(?:\s*\([^)]+\)|\s+[.\w]+(?!\[)))/g, function(match, other, type, equality, expression) {
|
|
||||||
return (other ? other + ' ' : '') + expression + equality + type;
|
|
||||||
});
|
|
||||||
|
|
||||||
// add a space so `define` is detected by the Dojo builder
|
|
||||||
source = source.replace(/(.)(define\()/, function(match, prelude, define) {
|
|
||||||
return prelude + (/^\S/.test(prelude) ? ' ' : '') + define;
|
|
||||||
});
|
|
||||||
|
|
||||||
// add trailing semicolon
|
|
||||||
if (source) {
|
|
||||||
source = source.replace(/[\s;]*?(\s*\/\/.*\s*|\s*\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\s*)*$/, ';$1');
|
|
||||||
}
|
|
||||||
// exit early if version snippet isn't found
|
|
||||||
var snippet = /VERSION\s*[=:]\s*([\'"])(.*?)\1/.exec(source);
|
|
||||||
if (!snippet) {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
// remove copyright header
|
|
||||||
source = source.replace(/^\/\**[\s\S]+?\*\/\n/, '');
|
|
||||||
|
|
||||||
// add new copyright header
|
|
||||||
var version = snippet[2];
|
|
||||||
source = licenseTemplate.replace('<%= VERSION %>', version) + '\n;' + source;
|
|
||||||
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
// expose `postprocess`
|
|
||||||
if (module != require.main) {
|
|
||||||
module.exports = postprocess;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// read the Lo-Dash source file from the first argument if the script
|
|
||||||
// was invoked directly (e.g. `node post-compile.js source.js`) and write to
|
|
||||||
// the same file
|
|
||||||
(function() {
|
|
||||||
var options = process.argv;
|
|
||||||
if (options.length < 3) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var filePath = options[options.length - 1],
|
|
||||||
source = fs.readFileSync(filePath, 'utf8');
|
|
||||||
|
|
||||||
fs.writeFileSync(filePath, postprocess(source), 'utf8');
|
|
||||||
}());
|
|
||||||
}
|
|
||||||
}());
|
|
||||||
@@ -1,461 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
;(function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/** The Node.js filesystem module */
|
|
||||||
var fs = require('fs');
|
|
||||||
|
|
||||||
/** Used to minify variables embedded in compiled strings */
|
|
||||||
var compiledVars = [
|
|
||||||
'args',
|
|
||||||
'argsIndex',
|
|
||||||
'argsLength',
|
|
||||||
'baseCreateCallback',
|
|
||||||
'callback',
|
|
||||||
'className',
|
|
||||||
'collection',
|
|
||||||
'conditions',
|
|
||||||
'ctor',
|
|
||||||
'errorClass',
|
|
||||||
'errorProto',
|
|
||||||
'guard',
|
|
||||||
'hasOwnProperty',
|
|
||||||
'index',
|
|
||||||
'indicatorObject',
|
|
||||||
'isArguments',
|
|
||||||
'isArray',
|
|
||||||
'isProto',
|
|
||||||
'isString',
|
|
||||||
'iterable',
|
|
||||||
'length',
|
|
||||||
'keys',
|
|
||||||
'lodash',
|
|
||||||
'nonEnum',
|
|
||||||
'nonEnumProps',
|
|
||||||
'object',
|
|
||||||
'objectProto',
|
|
||||||
'objectTypes',
|
|
||||||
'ownIndex',
|
|
||||||
'ownProps',
|
|
||||||
'result',
|
|
||||||
'skipErrorProps',
|
|
||||||
'skipProto',
|
|
||||||
'source',
|
|
||||||
'stringClass',
|
|
||||||
'stringProto',
|
|
||||||
'thisArg',
|
|
||||||
'toString'
|
|
||||||
];
|
|
||||||
|
|
||||||
/** Used to minify `iteratorTemplate` data properties */
|
|
||||||
var iteratorOptions = [
|
|
||||||
'args',
|
|
||||||
'array',
|
|
||||||
'bottom',
|
|
||||||
'firstArg',
|
|
||||||
'init',
|
|
||||||
'keys',
|
|
||||||
'loop',
|
|
||||||
'shadowedProps',
|
|
||||||
'top',
|
|
||||||
'useHas'
|
|
||||||
];
|
|
||||||
|
|
||||||
/** Used to minify variables and string values to a single character */
|
|
||||||
var minNames = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
|
|
||||||
minNames.push.apply(minNames, minNames.map(function(value) {
|
|
||||||
return value + value;
|
|
||||||
}));
|
|
||||||
|
|
||||||
/** Used to protect the specified properties from getting minified */
|
|
||||||
var propWhitelist = [
|
|
||||||
'Array',
|
|
||||||
'Boolean',
|
|
||||||
'Date',
|
|
||||||
'Error',
|
|
||||||
'Function',
|
|
||||||
'Math',
|
|
||||||
'Number',
|
|
||||||
'Object',
|
|
||||||
'RegExp',
|
|
||||||
'String',
|
|
||||||
'TypeError',
|
|
||||||
'VERSION',
|
|
||||||
'_',
|
|
||||||
'__bindData__',
|
|
||||||
'__chain__',
|
|
||||||
'__wrapped__',
|
|
||||||
'after',
|
|
||||||
'all',
|
|
||||||
'amd',
|
|
||||||
'any',
|
|
||||||
'argsClass',
|
|
||||||
'argsObject',
|
|
||||||
'array',
|
|
||||||
'assign',
|
|
||||||
'at',
|
|
||||||
'attachEvent',
|
|
||||||
'bind',
|
|
||||||
'bindAll',
|
|
||||||
'bindKey',
|
|
||||||
'cache',
|
|
||||||
'chain',
|
|
||||||
'clearTimeout',
|
|
||||||
'clone',
|
|
||||||
'cloneDeep',
|
|
||||||
'collect',
|
|
||||||
'compact',
|
|
||||||
'compose',
|
|
||||||
'configurable',
|
|
||||||
'contains',
|
|
||||||
'countBy',
|
|
||||||
'createCallback',
|
|
||||||
'criteria',
|
|
||||||
'curry',
|
|
||||||
'debounce',
|
|
||||||
'defaults',
|
|
||||||
'defer',
|
|
||||||
'delay',
|
|
||||||
'detect',
|
|
||||||
'difference',
|
|
||||||
'drop',
|
|
||||||
'each',
|
|
||||||
'enumerable',
|
|
||||||
'enumErrorProps',
|
|
||||||
'enumPrototypes',
|
|
||||||
'environment',
|
|
||||||
'escape',
|
|
||||||
'evaluate',
|
|
||||||
'every',
|
|
||||||
'exports',
|
|
||||||
'extend',
|
|
||||||
'fastBind',
|
|
||||||
'fastKeys',
|
|
||||||
'filter',
|
|
||||||
'find',
|
|
||||||
'findIndex',
|
|
||||||
'findKey',
|
|
||||||
'findLast',
|
|
||||||
'findLastIndex',
|
|
||||||
'findLastKey',
|
|
||||||
'findWhere',
|
|
||||||
'first',
|
|
||||||
'flatten',
|
|
||||||
'foldl',
|
|
||||||
'foldr',
|
|
||||||
'forEach',
|
|
||||||
'forEachRight',
|
|
||||||
'forIn',
|
|
||||||
'forInRight',
|
|
||||||
'forOwn',
|
|
||||||
'forOwnRight',
|
|
||||||
'function',
|
|
||||||
'functions',
|
|
||||||
'global',
|
|
||||||
'groupBy',
|
|
||||||
'has',
|
|
||||||
'head',
|
|
||||||
'identity',
|
|
||||||
'imports',
|
|
||||||
'include',
|
|
||||||
'index',
|
|
||||||
'indexBy',
|
|
||||||
'indexOf',
|
|
||||||
'initial',
|
|
||||||
'inject',
|
|
||||||
'interpolate',
|
|
||||||
'intersection',
|
|
||||||
'invert',
|
|
||||||
'invoke',
|
|
||||||
'isArguments',
|
|
||||||
'isArray',
|
|
||||||
'isBoolean',
|
|
||||||
'isDate',
|
|
||||||
'isElement',
|
|
||||||
'isEmpty',
|
|
||||||
'isEqual',
|
|
||||||
'isEqual',
|
|
||||||
'isFinite',
|
|
||||||
'isFinite',
|
|
||||||
'isFunction',
|
|
||||||
'isNaN',
|
|
||||||
'isNull',
|
|
||||||
'isNumber',
|
|
||||||
'isObject',
|
|
||||||
'isPlainObject',
|
|
||||||
'isRegExp',
|
|
||||||
'isString',
|
|
||||||
'isUndefined',
|
|
||||||
'keys',
|
|
||||||
'last',
|
|
||||||
'lastIndexOf',
|
|
||||||
'leading',
|
|
||||||
'map',
|
|
||||||
'max',
|
|
||||||
'maxWait',
|
|
||||||
'memoize',
|
|
||||||
'merge',
|
|
||||||
'methods',
|
|
||||||
'min',
|
|
||||||
'mixin',
|
|
||||||
'name',
|
|
||||||
'noConflict',
|
|
||||||
'nodeClass',
|
|
||||||
'nonEnumArgs',
|
|
||||||
'nonEnumShadows',
|
|
||||||
'now',
|
|
||||||
'null',
|
|
||||||
'number',
|
|
||||||
'object',
|
|
||||||
'omit',
|
|
||||||
'once',
|
|
||||||
'ownLast',
|
|
||||||
'pairs',
|
|
||||||
'parseInt',
|
|
||||||
'partial',
|
|
||||||
'partialRight',
|
|
||||||
'pick',
|
|
||||||
'pluck',
|
|
||||||
'pull',
|
|
||||||
'random',
|
|
||||||
'range',
|
|
||||||
'reduce',
|
|
||||||
'reduceRight',
|
|
||||||
'reject',
|
|
||||||
'remove',
|
|
||||||
'rest',
|
|
||||||
'result',
|
|
||||||
'runInContext',
|
|
||||||
'sample',
|
|
||||||
'select',
|
|
||||||
'setImmediate',
|
|
||||||
'setTimeout',
|
|
||||||
'shuffle',
|
|
||||||
'size',
|
|
||||||
'some',
|
|
||||||
'sortBy',
|
|
||||||
'sortedIndex',
|
|
||||||
'source',
|
|
||||||
'spliceObjects',
|
|
||||||
'string',
|
|
||||||
'support',
|
|
||||||
'tail',
|
|
||||||
'take',
|
|
||||||
'tap',
|
|
||||||
'template',
|
|
||||||
'templateSettings',
|
|
||||||
'throttle',
|
|
||||||
'times',
|
|
||||||
'toArray',
|
|
||||||
'trailing',
|
|
||||||
'transform',
|
|
||||||
'undefined',
|
|
||||||
'unescape',
|
|
||||||
'unindexedChars',
|
|
||||||
'union',
|
|
||||||
'uniq',
|
|
||||||
'unique',
|
|
||||||
'uniqueId',
|
|
||||||
'unzip',
|
|
||||||
'value',
|
|
||||||
'values',
|
|
||||||
'variable',
|
|
||||||
'where',
|
|
||||||
'window',
|
|
||||||
'without',
|
|
||||||
'wrap',
|
|
||||||
'writable',
|
|
||||||
'zip',
|
|
||||||
'zipObject'
|
|
||||||
];
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pre-process a given Lo-Dash `source`, preparing it for minification.
|
|
||||||
*
|
|
||||||
* @param {string} [source=''] The source to process.
|
|
||||||
* @param {Object} [options={}] The options object.
|
|
||||||
* @returns {string} Returns the processed source.
|
|
||||||
*/
|
|
||||||
function preprocess(source, options) {
|
|
||||||
source || (source = '');
|
|
||||||
options || (options = {});
|
|
||||||
|
|
||||||
// remove unrecognized JSDoc tags so the Closure Compiler won't complain
|
|
||||||
source = source.replace(/@(?:alias|category)\b.*/g, '');
|
|
||||||
|
|
||||||
if (options.isTemplate) {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove whitespace from string literals
|
|
||||||
source = source.replace(/^((?:[ "'\w]+:)? *)"[^"\n\\]*?(?:\\.[^"\n\\]*?)*"|'[^'\n\\]*?(?:\\.[^'\n\\]*?)*'/gm, function(string, left) {
|
|
||||||
// clip after an object literal property name or leading spaces
|
|
||||||
if (left) {
|
|
||||||
string = string.slice(left.length);
|
|
||||||
}
|
|
||||||
// avoids removing the '\n' of the `stringEscapes` object
|
|
||||||
string = string.replace(/\[object |delete |else (?!{)|function | in | instanceof |return\s+[\w"']|throw |typeof |use strict|var |@ |(["'])\\n\1|\\\\n|\\n|\s+/g, function(match) {
|
|
||||||
return match == false || match == '\\n' ? '' : match;
|
|
||||||
});
|
|
||||||
// unclip
|
|
||||||
return (left || '') + string;
|
|
||||||
});
|
|
||||||
|
|
||||||
// remove whitespace from `_.template` related regexes
|
|
||||||
source = source.replace(/reEmptyString\w+ *=.+/g, function(match) {
|
|
||||||
return match.replace(/ |\\n/g, '');
|
|
||||||
});
|
|
||||||
|
|
||||||
// remove newline from double-quoted strings in `_.template`
|
|
||||||
source = source
|
|
||||||
.replace('"__p += \'"', '"__p+=\'"')
|
|
||||||
.replace('"\';\n"', '"\';"')
|
|
||||||
|
|
||||||
// remove debug sourceURL use in `_.template`
|
|
||||||
source = source.replace(/(?:\s*\/\/.*\n)* *var sourceURL[^;]+;|\+ *sourceURL/g, '');
|
|
||||||
|
|
||||||
// minify internal properties
|
|
||||||
(function() {
|
|
||||||
var funcNames = [
|
|
||||||
'cacheIndexOf',
|
|
||||||
'cachePush',
|
|
||||||
'compareAscending',
|
|
||||||
'createCache',
|
|
||||||
'getObject',
|
|
||||||
'releaseObject',
|
|
||||||
'sortBy'
|
|
||||||
];
|
|
||||||
|
|
||||||
var props = [
|
|
||||||
'cache',
|
|
||||||
'criteria',
|
|
||||||
'index',
|
|
||||||
'value'
|
|
||||||
];
|
|
||||||
|
|
||||||
// minify other properties used in functions
|
|
||||||
var snippets = source.match(RegExp('^( *)(?:var|function) +(?:' + funcNames.join('|') + ')\\b[\\s\\S]+?\\n\\1}', 'gm'));
|
|
||||||
if (!snippets) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
snippets.forEach(function(snippet) {
|
|
||||||
var modified = snippet;
|
|
||||||
props.forEach(function(prop, index) {
|
|
||||||
// use minified names different than those chosen for `iteratorOptions`
|
|
||||||
var minName = minNames[iteratorOptions.length + index],
|
|
||||||
reBracketProp = RegExp("\\['(" + prop + ")'\\]", 'g'),
|
|
||||||
reDotProp = RegExp('\\.' + prop + '\\b', 'g'),
|
|
||||||
rePropColon = RegExp("([^?\\s])\\s*([\"'])?\\b" + prop + "\\2 *:", 'g');
|
|
||||||
|
|
||||||
modified = modified
|
|
||||||
.replace(reBracketProp, "['" + minName + "']")
|
|
||||||
.replace(reDotProp, "['" + minName + "']")
|
|
||||||
.replace(rePropColon, "$1'" + minName + "':");
|
|
||||||
});
|
|
||||||
|
|
||||||
// replace with modified snippet
|
|
||||||
source = source.replace(snippet, function() {
|
|
||||||
return modified;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}());
|
|
||||||
|
|
||||||
// minify all compilable snippets
|
|
||||||
var snippets = source.match(
|
|
||||||
RegExp([
|
|
||||||
// match the `iteratorTemplate`
|
|
||||||
'^( *)var iteratorTemplate\\b[\\s\\S]+?\\n\\1}',
|
|
||||||
// match methods created by `createIterator` calls
|
|
||||||
'createIterator\\((?:{|[a-zA-Z]+)[\\s\\S]*?\\);\\n',
|
|
||||||
// match variables storing `createIterator` options
|
|
||||||
'^( *)var [a-zA-Z]+IteratorOptions\\b[\\s\\S]+?\\n\\2}',
|
|
||||||
// match `baseUniq`, `cachePush`, `createCache`, `createIterator`, `getObject`, and `releaseObject` functions
|
|
||||||
'^( *)(?:var|function) +(?:baseUniq|cachePush|createCache|createIterator|getObject|releaseObject)\\b[\\s\\S]+?\\n\\3}'
|
|
||||||
].join('|'), 'gm')
|
|
||||||
) || [];
|
|
||||||
|
|
||||||
snippets.forEach(function(snippet, index) {
|
|
||||||
var isFunc = /\bfunction *[ \w]*\(/.test(snippet),
|
|
||||||
isIteratorTemplate = /var iteratorTemplate\b/.test(snippet),
|
|
||||||
modified = snippet;
|
|
||||||
|
|
||||||
// remove unnecessary semicolons in strings
|
|
||||||
modified = modified.replace(/;(?:}["']|(?:\\n|\s)*["']\s*\+\s*["'](?:\\n|\s)*})/g, function(match) {
|
|
||||||
return match.slice(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
// minify snippet variables / arguments
|
|
||||||
compiledVars.forEach(function(varName, index) {
|
|
||||||
var minName = minNames[index];
|
|
||||||
|
|
||||||
modified = modified.replace(/(["'])(?:(?!\1)[^\n\\]|\\.)*\1/g, function(match) {
|
|
||||||
return match.replace(RegExp('([^.])\\b' + varName + '\\b', 'g'), '$1' + minName);
|
|
||||||
});
|
|
||||||
|
|
||||||
// correct `typeof` string values
|
|
||||||
if (/^(?:boolean|function|object|number|string|undefined)$/.test(varName)) {
|
|
||||||
modified = modified.replace(RegExp('(= *)(["\'])' + minName + '\\2|(["\'])' + minName + '\\3( *=)', 'g'), function(match, prelude, preQuote, postQuote, postlude) {
|
|
||||||
return prelude
|
|
||||||
? prelude + preQuote + varName + preQuote
|
|
||||||
: postQuote + varName + postQuote + postlude;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// minify `createIterator` option property names
|
|
||||||
iteratorOptions.forEach(function(property, index) {
|
|
||||||
var minName = minNames[index];
|
|
||||||
|
|
||||||
// minify iterator option variables
|
|
||||||
modified = modified.replace(/(["'])(?:(?!\1)[^\n\\]|\\.)*\1/g, function(match, quote) {
|
|
||||||
return match.replace(RegExp('([^.])\\b' + property + '\\b', 'g'), '$1' + minName)
|
|
||||||
});
|
|
||||||
|
|
||||||
// minify iterator option properties, adding brackets so the Closure Compiler won't mung them
|
|
||||||
modified = modified.replace(RegExp('(["\'])(?:(?!\\1)[^\\n\\\\]|\\\\.)*\\1|\\.' + property + '\\b', 'g'), function(match, quote) {
|
|
||||||
return quote ? match : "['" + minName + "']";
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// replace with modified snippet
|
|
||||||
source = source.replace(snippet, function() {
|
|
||||||
return modified;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// add brackets to whitelisted properties so the Closure Compiler won't mung them
|
|
||||||
// http://code.google.com/closure/compiler/docs/api-tutorial3.html#export
|
|
||||||
source = source.replace(RegExp('(["\'])(?:(?!\\1)[^\\n\\\\]|\\\\.)*\\1|\\.(' + propWhitelist.join('|') + ')\\b', 'g'), function(match, quote, prop) {
|
|
||||||
return quote ? match : "['" + prop + "']";
|
|
||||||
});
|
|
||||||
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
// expose `preprocess`
|
|
||||||
if (module != require.main) {
|
|
||||||
module.exports = preprocess;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// read the Lo-Dash source file from the first argument if the script
|
|
||||||
// was invoked directly (e.g. `node pre-compile.js source.js`) and write to
|
|
||||||
// the same file
|
|
||||||
(function() {
|
|
||||||
var options = process.argv;
|
|
||||||
if (options.length < 3) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var filePath = options[options.length - 1],
|
|
||||||
isTemplate = options.indexOf('-t') > -1 || options.indexOf('--template') > -1,
|
|
||||||
source = fs.readFileSync(filePath, 'utf8');
|
|
||||||
|
|
||||||
fs.writeFileSync(filePath, preprocess(source, {
|
|
||||||
'isTemplate': isTemplate
|
|
||||||
}), 'utf8');
|
|
||||||
}());
|
|
||||||
}
|
|
||||||
}());
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
;(function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/** Load Node.js modules */
|
|
||||||
var fs = require('fs'),
|
|
||||||
path = require('path');
|
|
||||||
|
|
||||||
/** Load other modules */
|
|
||||||
var _ = require('../lodash.js');
|
|
||||||
|
|
||||||
/** Used to indicate if running in Windows */
|
|
||||||
var isWindows = process.platform == 'win32';
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The path separator.
|
|
||||||
*
|
|
||||||
* @memberOf util.path
|
|
||||||
* @type string
|
|
||||||
*/
|
|
||||||
var sep = path.sep || (isWindows ? '\\' : '/');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The escaped path separator used for inclusion in RegExp strings.
|
|
||||||
*
|
|
||||||
* @memberOf util.path
|
|
||||||
* @type string
|
|
||||||
*/
|
|
||||||
var sepEscaped = sep.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
|
|
||||||
/** Used to determine if a path is prefixed with a drive letter, dot, or slash */
|
|
||||||
var rePrefixed = RegExp('^(?:' + (isWindows ? '[a-zA-Z]:|' : '') + '\\.?)' + sepEscaped);
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the given `dirname` directory, without throwing errors for existing
|
|
||||||
* directories and making parent directories as needed.
|
|
||||||
*
|
|
||||||
* @memberOf util.fs
|
|
||||||
* @param {string} dirname The path of the directory.
|
|
||||||
* @param {number|string} [mode='0777'] The permission mode.
|
|
||||||
*/
|
|
||||||
function mkdirpSync(dirname, mode) {
|
|
||||||
// ensure relative paths are prefixed with `./`
|
|
||||||
if (!rePrefixed.test(dirname)) {
|
|
||||||
dirname = '.' + sep + dirname;
|
|
||||||
}
|
|
||||||
dirname.split(sep).reduce(function(currPath, segment) {
|
|
||||||
currPath += sep + segment;
|
|
||||||
try {
|
|
||||||
currPath = fs.realpathSync(currPath);
|
|
||||||
} catch(e) {
|
|
||||||
fs.mkdirSync(currPath, mode);
|
|
||||||
}
|
|
||||||
return currPath;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The utility object.
|
|
||||||
*
|
|
||||||
* @type Object
|
|
||||||
*/
|
|
||||||
var util = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The file system object.
|
|
||||||
*
|
|
||||||
* @memberOf util
|
|
||||||
* @type Object
|
|
||||||
*/
|
|
||||||
'fs': _.defaults(_.cloneDeep(fs), {
|
|
||||||
'existsSync': fs.existsSync || path.existsSync,
|
|
||||||
'mkdirpSync': mkdirpSync
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The path object.
|
|
||||||
*
|
|
||||||
* @memberOf util
|
|
||||||
* @type Object
|
|
||||||
*/
|
|
||||||
'path': _.defaults(_.cloneDeep(path), {
|
|
||||||
'sep': sep,
|
|
||||||
'sepEscaped': sepEscaped
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
// expose
|
|
||||||
module.exports = util;
|
|
||||||
}());
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "lodash",
|
"name": "lodash",
|
||||||
"repo": "bestiejs/lodash",
|
"repo": "bestiejs/lodash",
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"description": "A low-level utility library delivering consistency, customization, performance, and extra features.",
|
"description": "A utility library delivering consistency, customization, performance, and extras.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": [
|
"scripts": [
|
||||||
"index.js",
|
"index.js",
|
||||||
|
|||||||
15
package.json
15
package.json
@@ -43,18 +43,21 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/bestiejs/lodash.git"
|
"url": "https://github.com/bestiejs/lodash.git"
|
||||||
},
|
},
|
||||||
"bin": {
|
|
||||||
"lodash": "./build.js"
|
|
||||||
},
|
|
||||||
"engines": [
|
"engines": [
|
||||||
"node",
|
"node",
|
||||||
"rhino"
|
"rhino"
|
||||||
],
|
],
|
||||||
"files": [
|
"files": [
|
||||||
"build.js",
|
|
||||||
"LICENSE.txt",
|
|
||||||
"dist/lodash.js",
|
"dist/lodash.js",
|
||||||
"dist/lodash.min.js",
|
"dist/lodash.min.js",
|
||||||
|
"dist/lodash.backbone.js",
|
||||||
|
"dist/lodash.backbone.min.js",
|
||||||
|
"dist/lodash.compat.js",
|
||||||
|
"dist/lodash.compat.min.js",
|
||||||
|
"dist/lodash.legacy.js",
|
||||||
|
"dist/lodash.legacy.min.js",
|
||||||
|
"dist/lodash.mobile.js",
|
||||||
|
"dist/lodash.mobile.min.js",
|
||||||
"dist/lodash.underscore.js",
|
"dist/lodash.underscore.js",
|
||||||
"dist/lodash.underscore.min.js"
|
"dist/lodash.underscore.min.js"
|
||||||
],
|
],
|
||||||
@@ -75,12 +78,10 @@
|
|||||||
"*.map",
|
"*.map",
|
||||||
"*.md",
|
"*.md",
|
||||||
"*.txt",
|
"*.txt",
|
||||||
"build.js",
|
|
||||||
"lodash.js",
|
"lodash.js",
|
||||||
"index.js",
|
"index.js",
|
||||||
"bower.json",
|
"bower.json",
|
||||||
"component.json",
|
"component.json",
|
||||||
"build",
|
|
||||||
"doc",
|
"doc",
|
||||||
"modularize",
|
"modularize",
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
|||||||
@@ -9,10 +9,6 @@ done
|
|||||||
echo "Testing in node..."
|
echo "Testing in node..."
|
||||||
node test.js ../dist/lodash.js && node test.js ../dist/lodash.min.js
|
node test.js ../dist/lodash.js && node test.js ../dist/lodash.min.js
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Testing build..."
|
|
||||||
node test-build.js
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Testing in a browser..."
|
echo "Testing in a browser..."
|
||||||
open index.html
|
open index.html
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
<ul>
|
|
||||||
<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>
|
|
||||||
</ul>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<% print("Hello " + epithet); %>.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Hello ${ name }!
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Hallå {{ name }}!
|
|
||||||
1837
test/test-build.js
1837
test/test-build.js
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user