presentations/highlight-js/tools/tasks.js

249 lines
6.8 KiB
JavaScript
Raw Permalink Normal View History

2018-12-07 08:48:05 -06:00
'use strict';
let _ = require('lodash');
let del = require('del');
let gear = require('gear');
let path = require('path');
let utility = require('./utility');
let parseHeader = utility.parseHeader;
let tasks = require('gear-lib');
tasks.clean = function(directories, blobs, done) {
directories = _.isString(directories) ? [directories] : directories;
return del(directories).then(() => done(null, blobs));
};
tasks.clean.type = 'collect';
// Depending on the languages required for the current language being
// processed, this task reorders it's dependencies first then include the
// language.
tasks.reorderDeps = function(options, blobs, done) {
let buffer = {},
newBlobOrder = [];
_.each(blobs, function(blob) {
let basename = path.basename(blob.name),
fileInfo = parseHeader(blob.result),
extra = { blob: blob, processed: false };
buffer[basename] = _.merge(extra, fileInfo || {});
});
function pushInBlob(object) {
if(!object.processed) {
object.processed = true;
newBlobOrder.push(object.blob);
}
}
_.each(buffer, function(buf) {
let object;
if(buf.Requires) {
_.each(buf.Requires, function(language) {
object = buffer[language];
pushInBlob(object);
});
}
pushInBlob(buf);
});
done(null, newBlobOrder);
};
tasks.reorderDeps.type = 'collect';
tasks.template = function(template, blob, done) {
template = template || '';
let filename = path.basename(blob.name),
basename = path.basename(filename, '.js'),
content = _.template(template)({
name: basename,
filename: filename,
content: blob.result.trim()
});
return done(null, new gear.Blob(content, blob));
};
tasks.templateAll = function(options, blobs, done) {
return options.callback(blobs)
.then(function(data) {
let template = options.template || data.template,
content = _.template(template)(data);
return done(null, [new gear.Blob(content)]);
})
.catch(done);
};
tasks.templateAll.type = 'collect';
tasks.rename = function(options, blob, done) {
options = options || {};
let name = blob.name,
ext = new RegExp(path.extname(name) + '$');
name = name.replace(ext, options.extname);
return done(null, new gear.Blob(blob.result, { name: name }));
};
// Adds the contributors from `AUTHORS.en.txt` onto the `package.json` file
// and moves the result into the `build` directory.
tasks.buildPackage = function(json, blob, done) {
let result,
lines = blob.result.split(/\r?\n/),
regex = /^- (.*) <(.*)>$/;
json.contributors = _.transform(lines, function(result, line) {
let matches = line.match(regex);
if(matches) {
result.push({
name: matches[1],
email: matches[2]
});
}
}, []);
result = JSON.stringify(json, null, ' ');
return done(null, new gear.Blob(result, blob));
};
// Mainly for replacing the keys of `utility.REPLACES` for it's values while
// skipping over strings, regular expressions, or comments. However, this is
// pretty generic so long as you use the `utility.replace` function, you can
// replace a regular expression with a string.
tasks.replaceSkippingStrings = function(params, blob, done) {
let content = blob.result,
length = content.length,
offset = 0,
replace = params.replace || '',
regex = params.regex,
starts = /\/\/|['"\/]/,
result = [],
chunk, end, match, start, terminator;
while(offset < length) {
chunk = content.slice(offset);
match = chunk.match(starts);
end = match ? match.index : length;
chunk = content.slice(offset, end + offset);
result.push(chunk.replace(regex, replace));
offset += end;
if(match) {
// We found a starter sequence: either a `//` or a "quote"
// In the case of `//` our terminator is the end of line.
// Otherwise it's either a matching quote or an escape symbol.
terminator = match[0] !== '//' ? new RegExp(`[${match[0]}\\\\]`)
: /$/m;
start = offset;
offset += 1;
while(true) {
chunk = content.slice(offset);
match = chunk.match(terminator);
if(!match) {
return done('Unmatched quote');
}
if(match[0] === '\\') {
offset += match.index + 2;
} else {
offset += match.index + 1;
result.push(content.slice(start, offset));
break;
}
}
}
}
return done(null, new gear.Blob(result.join(''), blob));
};
tasks.filter = function(callback, blobs, done) {
let filteredBlobs = _.filter(blobs, callback);
// Re-add in blobs required from header definition
_.each(filteredBlobs, function(blob) {
let dirname = path.dirname(blob.name),
content = blob.result,
fileInfo = parseHeader(content);
if(fileInfo && fileInfo.Requires) {
_.each(fileInfo.Requires, function(language) {
let filename = `${dirname}/${language}`,
fileFound = _.find(filteredBlobs, { name: filename });
if(!fileFound) {
filteredBlobs.push(
_.find(blobs, { name: filename }));
}
});
}
});
return done(null, filteredBlobs);
};
tasks.filter.type = 'collect';
tasks.readSnippet = function(options, blob, done) {
let name = path.basename(blob.name, '.js'),
fileInfo = parseHeader(blob.result),
snippetName = path.join('test', 'detect', name, 'default.txt');
function onRead(error, blob) {
if(error) return done(error); // ignore missing snippets
let meta = { name: `${name}.js`, fileInfo: fileInfo };
return done(null, new gear.Blob(blob.result, meta));
}
gear.Blob.readFile(snippetName, 'utf8', onRead, false);
};
tasks.insertLicenseTag = function(options, blob, done) {
let hljsVersion = require('../package').version,
licenseTag = `/*! highlight.js v${hljsVersion} | ` +
`BSD3 License | git.io/hljslicense */\n`;
return done(null, new gear.Blob(licenseTag + blob.result, blob));
};
// Packages up included languages into the core `highlight.js` and moves the
// result into the `build` directory.
tasks.packageFiles = function(options, blobs, done) {
let content,
coreFile = _.head(blobs),
languages = _.tail(blobs),
lines = coreFile.result
.replace(utility.regex.header, '')
.split('\n\n'),
lastLine = _.last(lines),
langStr = _.reduce(languages, (str, language) =>
`${str + language.result}\n`, '');
lines[lines.length - 1] = langStr.trim();
lines = lines.concat(lastLine);
content = lines.join('\n\n');
return done(null, [new gear.Blob(content)]);
};
tasks.packageFiles.type = 'collect';
module.exports = new gear.Registry({ tasks: tasks });