Update translation hashing (#5025)

* Update translation hashing

* Move gulp-rename
This commit is contained in:
Paulus Schoutsen 2020-03-02 02:36:00 -08:00 committed by GitHub
parent 319a3b4943
commit d74fe6ed52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 274 additions and 396 deletions

View File

@ -24,7 +24,7 @@ gulp.task(
gulp.parallel("gen-icons-app", "gen-icons-mdi"), gulp.parallel("gen-icons-app", "gen-icons-mdi"),
"gen-pages-dev", "gen-pages-dev",
"gen-index-app-dev", "gen-index-app-dev",
gulp.series("create-test-translation", "build-translations") "build-translations"
), ),
"copy-static", "copy-static",
"webpack-watch-app" "webpack-watch-app"

View File

@ -2,6 +2,7 @@ const gulp = require("gulp");
const path = require("path"); const path = require("path");
const fs = require("fs"); const fs = require("fs");
const paths = require("../paths"); const paths = require("../paths");
const { mapFiles } = require("../util");
const ICON_PACKAGE_PATH = path.resolve( const ICON_PACKAGE_PATH = path.resolve(
__dirname, __dirname,
@ -57,20 +58,6 @@ function generateIconset(iconsetName, iconNames) {
return `<ha-iconset-svg name="${iconsetName}" size="24"><svg><defs>${iconDefs}</defs></svg></ha-iconset-svg>`; return `<ha-iconset-svg name="${iconsetName}" size="24"><svg><defs>${iconDefs}</defs></svg></ha-iconset-svg>`;
} }
// Helper function to map recursively over files in a folder and it's subfolders
function mapFiles(startPath, filter, mapFunc) {
const files = fs.readdirSync(startPath);
for (let i = 0; i < files.length; i++) {
const filename = path.join(startPath, files[i]);
const stat = fs.lstatSync(filename);
if (stat.isDirectory()) {
mapFiles(filename, filter, mapFunc);
} else if (filename.indexOf(filter) >= 0) {
mapFunc(filename);
}
}
}
// Find all icons used by the project. // Find all icons used by the project.
function findIcons(searchPath, iconsetName) { function findIcons(searchPath, iconsetName) {
const iconRegex = new RegExp(`${iconsetName}:[\\w-]+`, "g"); const iconRegex = new RegExp(`${iconsetName}:[\\w-]+`, "g");

View File

@ -1,14 +1,17 @@
const crypto = require("crypto");
const del = require("del"); const del = require("del");
const path = require("path"); const path = require("path");
const source = require("vinyl-source-stream");
const vinylBuffer = require("vinyl-buffer");
const gulp = require("gulp"); const gulp = require("gulp");
const fs = require("fs"); const fs = require("fs");
const foreach = require("gulp-foreach"); const foreach = require("gulp-foreach");
const hash = require("gulp-hash");
const hashFilename = require("gulp-hash-filename");
const merge = require("gulp-merge-json"); const merge = require("gulp-merge-json");
const minify = require("gulp-jsonminify"); const minify = require("gulp-jsonminify");
const rename = require("gulp-rename"); const rename = require("gulp-rename");
const transform = require("gulp-json-transform"); const transform = require("gulp-json-transform");
const { mapFiles } = require("../util");
const env = require("../env");
const inDir = "translations"; const inDir = "translations";
const workDir = "build-translations"; const workDir = "build-translations";
@ -39,8 +42,6 @@ const TRANSLATION_FRAGMENTS = [
"developer-tools", "developer-tools",
]; ];
const tasks = [];
function recursiveFlatten(prefix, data) { function recursiveFlatten(prefix, data) {
let output = {}; let output = {};
Object.keys(data).forEach(function(key) { Object.keys(data).forEach(function(key) {
@ -116,11 +117,9 @@ function lokaliseTransform(data, original, file) {
return output; return output;
} }
let taskName = "clean-translations"; gulp.task("clean-translations", function() {
gulp.task(taskName, function() { return del([workDir]);
return del([`${outDir}/**/*.json`]);
}); });
tasks.push(taskName);
gulp.task("ensure-translations-build-dir", (done) => { gulp.task("ensure-translations-build-dir", (done) => {
if (!fs.existsSync(workDir)) { if (!fs.existsSync(workDir)) {
@ -129,27 +128,21 @@ gulp.task("ensure-translations-build-dir", (done) => {
done(); done();
}); });
taskName = "create-test-metadata"; gulp.task("create-test-metadata", function(cb) {
gulp.task( fs.writeFile(
taskName, workDir + "/testMetadata.json",
gulp.series("ensure-translations-build-dir", function writeTestMetaData(cb) { JSON.stringify({
fs.writeFile( test: {
workDir + "/testMetadata.json", nativeName: "Test",
JSON.stringify({ },
test: { }),
nativeName: "Test", cb
}, );
}), });
cb
);
})
);
tasks.push(taskName);
taskName = "create-test-translation";
gulp.task( gulp.task(
taskName, "create-test-translation",
gulp.series("create-test-metadata", function() { gulp.series("create-test-metadata", function createTestTranslation() {
return gulp return gulp
.src("src/translations/en.json") .src("src/translations/en.json")
.pipe( .pipe(
@ -161,7 +154,6 @@ gulp.task(
.pipe(gulp.dest(workDir)); .pipe(gulp.dest(workDir));
}) })
); );
tasks.push(taskName);
/** /**
* This task will build a master translation file, to be used as the base for * This task will build a master translation file, to be used as the base for
@ -172,235 +164,215 @@ tasks.push(taskName);
* project is buildable immediately after merging new translation keys, since * project is buildable immediately after merging new translation keys, since
* the Lokalise update to translations/en.json will not happen immediately. * the Lokalise update to translations/en.json will not happen immediately.
*/ */
taskName = "build-master-translation"; gulp.task("build-master-translation", function() {
gulp.task( return gulp
taskName, .src("src/translations/en.json")
gulp.series("clean-translations", function() { .pipe(
return gulp transform(function(data, file) {
.src("src/translations/en.json") return lokaliseTransform(data, data, file);
.pipe( })
transform(function(data, file) { )
return lokaliseTransform(data, data, file); .pipe(rename("translationMaster.json"))
}) .pipe(gulp.dest(workDir));
) });
.pipe(rename("translationMaster.json"))
.pipe(gulp.dest(workDir));
})
);
tasks.push(taskName);
taskName = "build-merged-translations"; gulp.task("build-merged-translations", function() {
gulp.task( return gulp
taskName, .src([inDir + "/*.json", workDir + "/test.json"], { allowEmpty: true })
gulp.series("build-master-translation", function() { .pipe(
return gulp transform(function(data, file) {
.src([inDir + "/*.json", workDir + "/test.json"], { allowEmpty: true }) return lokaliseTransform(data, data, file);
.pipe( })
transform(function(data, file) { )
return lokaliseTransform(data, data, file); .pipe(
}) foreach(function(stream, file) {
) // For each language generate a merged json file. It begins with the master
.pipe( // translation as a failsafe for untranslated strings, and merges all parent
foreach(function(stream, file) { // tags into one file for each specific subtag
// For each language generate a merged json file. It begins with the master //
// translation as a failsafe for untranslated strings, and merges all parent // TODO: This is a naive interpretation of BCP47 that should be improved.
// tags into one file for each specific subtag // Will be OK for now as long as we don't have anything more complicated
// // than a base translation + region.
// TODO: This is a naive interpretation of BCP47 that should be improved. const tr = path.basename(file.history[0], ".json");
// Will be OK for now as long as we don't have anything more complicated const subtags = tr.split("-");
// than a base translation + region. const src = [workDir + "/translationMaster.json"];
const tr = path.basename(file.history[0], ".json"); for (let i = 1; i <= subtags.length; i++) {
const subtags = tr.split("-"); const lang = subtags.slice(0, i).join("-");
const src = [workDir + "/translationMaster.json"]; if (lang === "test") {
for (let i = 1; i <= subtags.length; i++) { src.push(workDir + "/test.json");
const lang = subtags.slice(0, i).join("-"); } else if (lang !== "en") {
if (lang === "test") { src.push(inDir + "/" + lang + ".json");
src.push(workDir + "/test.json");
} else if (lang !== "en") {
src.push(inDir + "/" + lang + ".json");
}
} }
return gulp }
.src(src, { allowEmpty: true }) return gulp
.pipe(transform((data) => emptyFilter(data))) .src(src, { allowEmpty: true })
.pipe( .pipe(transform((data) => emptyFilter(data)))
merge({ .pipe(
fileName: tr + ".json", merge({
}) fileName: tr + ".json",
) })
.pipe(gulp.dest(fullDir)); )
}) .pipe(gulp.dest(fullDir));
); })
}) );
); });
tasks.push(taskName);
var taskName;
const splitTasks = []; const splitTasks = [];
TRANSLATION_FRAGMENTS.forEach((fragment) => { TRANSLATION_FRAGMENTS.forEach((fragment) => {
taskName = "build-translation-fragment-" + fragment; taskName = "build-translation-fragment-" + fragment;
gulp.task( gulp.task(taskName, function() {
taskName, // Return only the translations for this fragment.
gulp.series("build-merged-translations", function() { return gulp
// Return only the translations for this fragment. .src(fullDir + "/*.json")
return gulp .pipe(
.src(fullDir + "/*.json") transform((data) => ({
.pipe( ui: {
transform((data) => ({ panel: {
ui: { [fragment]: data.ui.panel[fragment],
panel: {
[fragment]: data.ui.panel[fragment],
},
}, },
})) },
) }))
.pipe(gulp.dest(workDir + "/" + fragment)); )
}) .pipe(gulp.dest(workDir + "/" + fragment));
); });
tasks.push(taskName);
splitTasks.push(taskName); splitTasks.push(taskName);
}); });
taskName = "build-translation-core"; taskName = "build-translation-core";
gulp.task( gulp.task(taskName, function() {
taskName, // Remove the fragment translations from the core translation.
gulp.series("build-merged-translations", function() { return gulp
// Remove the fragment translations from the core translation. .src(fullDir + "/*.json")
return gulp .pipe(
.src(fullDir + "/*.json") transform((data) => {
.pipe( TRANSLATION_FRAGMENTS.forEach((fragment) => {
transform((data) => { delete data.ui.panel[fragment];
TRANSLATION_FRAGMENTS.forEach((fragment) => { });
delete data.ui.panel[fragment]; return data;
}); })
return data; )
}) .pipe(gulp.dest(coreDir));
) });
.pipe(gulp.dest(coreDir));
})
);
tasks.push(taskName);
splitTasks.push(taskName); splitTasks.push(taskName);
taskName = "build-flattened-translations"; gulp.task("build-flattened-translations", function() {
gulp.task( // Flatten the split versions of our translations, and move them into outDir
taskName, return gulp
gulp.series(...splitTasks, function() { .src(
// Flatten the split versions of our translations, and move them into outDir TRANSLATION_FRAGMENTS.map(
return gulp (fragment) => workDir + "/" + fragment + "/*.json"
.src( ).concat(coreDir + "/*.json"),
TRANSLATION_FRAGMENTS.map( { base: workDir }
(fragment) => workDir + "/" + fragment + "/*.json" )
).concat(coreDir + "/*.json"), .pipe(
{ base: workDir } transform(function(data) {
) // Polymer.AppLocalizeBehavior requires flattened json
.pipe( return flatten(data);
transform(function(data) { })
// Polymer.AppLocalizeBehavior requires flattened json )
return flatten(data); .pipe(minify())
}) .pipe(
) rename((filePath) => {
.pipe(minify()) if (filePath.dirname === "core") {
.pipe(hashFilename()) filePath.dirname = "";
.pipe( }
rename((filePath) => { })
if (filePath.dirname === "core") { )
filePath.dirname = ""; .pipe(gulp.dest(outDir));
} });
})
)
.pipe(gulp.dest(outDir));
})
);
tasks.push(taskName);
taskName = "build-translation-fingerprints"; const fingerprints = {};
gulp.task(
taskName,
gulp.series("build-flattened-translations", function() {
return gulp
.src(outDir + "/**/*.json")
.pipe(
rename({
extname: "",
})
)
.pipe(
hash({
algorithm: "md5",
hashLength: 32,
template: "<%= name %>.json",
})
)
.pipe(hash.manifest("translationFingerprints.json"))
.pipe(
transform(function(data) {
// After generating fingerprints of our translation files, consolidate
// all translation fragment fingerprints under the translation name key
const newData = {};
Object.entries(data).forEach(([key, value]) => {
const [path, _md5] = key.rsplit("-", 1);
// let translation = key;
let translation = path;
const parts = translation.split("/");
if (parts.length === 2) {
translation = parts[1];
}
if (!(translation in newData)) {
newData[translation] = {
fingerprints: {},
};
}
newData[translation].fingerprints[path] = value;
});
return newData;
})
)
.pipe(gulp.dest(workDir));
})
);
tasks.push(taskName);
taskName = "build-translations";
gulp.task( gulp.task(
taskName, "build-translation-fingerprints",
gulp.series("build-translation-fingerprints", function() { function fingerprintTranslationFiles() {
return gulp // Fingerprint full file of each language
.src( const files = fs.readdirSync(fullDir);
[ for (let i = 0; i < files.length; i++) {
"src/translations/translationMetadata.json", fingerprints[files[i].split(".")[0]] = {
workDir + "/testMetadata.json", // In dev we create fake hashes
workDir + "/translationFingerprints.json", hash: env.isProdBuild
], ? crypto
{ allowEmpty: true } .createHash("md5")
) .update(fs.readFileSync(path.join(fullDir, files[i]), "utf-8"))
.pipe(merge({})) .digest("hex")
.pipe( : "dev",
transform(function(data) { };
const newData = {}; }
Object.entries(data).forEach(([key, value]) => {
// Filter out translations without native name.
if (data[key].nativeName) {
newData[key] = data[key];
} else {
console.warn(
`Skipping language ${key}. Native name was not translated.`
);
}
if (data[key]) newData[key] = value;
});
return newData;
})
)
.pipe(
transform((data) => ({
fragments: TRANSLATION_FRAGMENTS,
translations: data,
}))
)
.pipe(rename("translationMetadata.json"))
.pipe(gulp.dest(workDir));
})
);
tasks.push(taskName);
module.exports = tasks; mapFiles(outDir, ".json", (filename) => {
const parsed = path.parse(filename);
// nl.json -> nl-<hash>.json
if (!(parsed.name in fingerprints)) {
throw new Error(`Unable to find hash for ${filename}`);
}
fs.renameSync(
filename,
`${parsed.dir}/${parsed.name}-${fingerprints[parsed.name].hash}${
parsed.ext
}`
);
});
const stream = source("translationFingerprints.json");
stream.write(JSON.stringify(fingerprints));
process.nextTick(() => stream.end());
return stream.pipe(vinylBuffer()).pipe(gulp.dest(workDir));
}
);
gulp.task(
"build-translations",
gulp.series(
"clean-translations",
"ensure-translations-build-dir",
env.isProdBuild ? (done) => done() : "create-test-translation",
"build-master-translation",
"build-merged-translations",
gulp.parallel(...splitTasks),
"build-flattened-translations",
"build-translation-fingerprints",
function writeMetadata() {
return gulp
.src(
[
"src/translations/translationMetadata.json",
workDir + "/testMetadata.json",
workDir + "/translationFingerprints.json",
],
{ allowEmpty: true }
)
.pipe(merge({}))
.pipe(
transform(function(data) {
const newData = {};
Object.entries(data).forEach(([key, value]) => {
// Filter out translations without native name.
if (data[key].nativeName) {
newData[key] = data[key];
} else {
console.warn(
`Skipping language ${key}. Native name was not translated.`
);
}
if (data[key]) newData[key] = value;
});
return newData;
})
)
.pipe(
transform((data) => ({
fragments: TRANSLATION_FRAGMENTS,
translations: data,
}))
)
.pipe(rename("translationMetadata.json"))
.pipe(gulp.dest(workDir));
}
)
);

16
build-scripts/util.js Normal file
View File

@ -0,0 +1,16 @@
const path = require("path");
const fs = require("fs");
// Helper function to map recursively over files in a folder and it's subfolders
module.exports.mapFiles = function mapFiles(startPath, filter, mapFunc) {
const files = fs.readdirSync(startPath);
for (let i = 0; i < files.length; i++) {
const filename = path.join(startPath, files[i]);
const stat = fs.lstatSync(filename);
if (stat.isDirectory()) {
mapFiles(filename, filter, mapFunc);
} else if (filename.indexOf(filter) >= 0) {
mapFunc(filename);
}
}
};

View File

@ -148,11 +148,17 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
// Create an object mapping browser urls to their paths during build // Create an object mapping browser urls to their paths during build
const translationMetadata = require("../build-translations/translationMetadata.json"); const translationMetadata = require("../build-translations/translationMetadata.json");
const workBoxTranslationsTemplatedURLs = {}; const workBoxTranslationsTemplatedURLs = {};
const englishFP = translationMetadata.translations.en.fingerprints; const englishFilename = `en-${translationMetadata.translations.en.hash}.json`;
Object.keys(englishFP).forEach((key) => {
// core
workBoxTranslationsTemplatedURLs[
`/static/translations/${englishFilename}`
] = `build-translations/output/${englishFilename}`;
Object.keys(translationMetadata.fragments).forEach((fragment) => {
workBoxTranslationsTemplatedURLs[ workBoxTranslationsTemplatedURLs[
`/static/translations/${englishFP[key]}` `/static/translations/${fragment}/${englishFilename}`
] = `build-translations/output/${key}.json`; ] = `build-translations/output/${fragment}/${englishFilename}`;
}); });
config.plugins.push( config.plugins.push(

View File

@ -145,13 +145,11 @@
"fs-extra": "^7.0.1", "fs-extra": "^7.0.1",
"gulp": "^4.0.0", "gulp": "^4.0.0",
"gulp-foreach": "^0.1.0", "gulp-foreach": "^0.1.0",
"gulp-hash": "^4.2.2",
"gulp-hash-filename": "^2.0.1",
"gulp-insert": "^0.5.0", "gulp-insert": "^0.5.0",
"gulp-json-transform": "^0.4.6", "gulp-json-transform": "^0.4.6",
"gulp-jsonminify": "^1.1.0", "gulp-jsonminify": "^1.1.0",
"gulp-merge-json": "^1.3.1", "gulp-merge-json": "^1.3.1",
"gulp-rename": "^1.4.0", "gulp-rename": "^2.0.0",
"gulp-zopfli-green": "^3.0.1", "gulp-zopfli-green": "^3.0.1",
"html-loader": "^0.5.5", "html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
@ -174,6 +172,8 @@
"tslint-eslint-rules": "^5.4.0", "tslint-eslint-rules": "^5.4.0",
"tslint-plugin-prettier": "^2.0.1", "tslint-plugin-prettier": "^2.0.1",
"typescript": "^3.7.2", "typescript": "^3.7.2",
"vinyl-buffer": "^1.0.1",
"vinyl-source-stream": "^2.0.0",
"web-component-tester": "^6.9.2", "web-component-tester": "^6.9.2",
"webpack": "^4.40.2", "webpack": "^4.40.2",
"webpack-cli": "^3.3.9", "webpack-cli": "^3.3.9",

View File

@ -34,7 +34,7 @@
"nativeName": "English" "nativeName": "English"
}, },
"eo": { "eo": {
"navtiveName": "Esperanto" "nativeName": "Esperanto"
}, },
"es": { "es": {
"nativeName": "Español" "nativeName": "Español"

View File

@ -95,7 +95,7 @@ export interface Panels {
export interface Translation { export interface Translation {
nativeName: string; nativeName: string;
isRTL: boolean; isRTL: boolean;
fingerprints: { [fragment: string]: string }; hash: string;
} }
export interface TranslationMetadata { export interface TranslationMetadata {

View File

@ -122,8 +122,11 @@ export async function getTranslation(
} }
throw new Error("Language en is not found in metadata"); throw new Error("Language en is not found in metadata");
} }
const fingerprint =
metadata.fingerprints[fragment ? `${fragment}/${language}` : language]; // nl-abcd.jon or logbook/nl-abcd.json
const fingerprint = `${fragment ? fragment + "/" : ""}${language}-${
metadata.hash
}.json`;
// Fetch translation from the server // Fetch translation from the server
if (!translations[fingerprint]) { if (!translations[fingerprint]) {

148
yarn.lock
View File

@ -3968,7 +3968,7 @@ binary-extensions@^1.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
bl@^1.0.0: bl@^1.0.0, bl@^1.2.1:
version "1.2.2" version "1.2.2"
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==
@ -5951,11 +5951,6 @@ es6-object-assign@^1.1.0:
resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c"
integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw= integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=
es6-promise@^2.1.1:
version "2.3.0"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-2.3.0.tgz#96edb9f2fdb01995822b263dd8aadab6748181bc"
integrity sha1-lu258v2wGZWCKyY92KratnSBgbw=
es6-promise@^4.0.3, es6-promise@^4.0.5: es6-promise@^4.0.3, es6-promise@^4.0.5:
version "4.2.6" version "4.2.6"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f"
@ -7261,22 +7256,6 @@ gulp-foreach@^0.1.0:
gulp-util "~2.2.14" gulp-util "~2.2.14"
through2 "~0.6.3" through2 "~0.6.3"
gulp-hash-filename@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/gulp-hash-filename/-/gulp-hash-filename-2.0.1.tgz#c30656261a9b622d636766e48b8297125b4ddde8"
integrity sha512-pMg5owb8Dt0wqjgPx/TFbU3c5ckD16rrgo0BTm9PQ3pVC1Zsgw7AYx1+DP2t31JoUTeN1/dPuXNWnCNvN/wj7A==
gulp-hash@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/gulp-hash/-/gulp-hash-4.2.2.tgz#2cf4ad081ef7a65393a51e3df58f514f388f4523"
integrity sha512-uWCjiy7ZXCPu4aaTM454+ImCnrR+07MKdwpunDZU0I7oUd5+SfyDxxhYzgpzSRVSlCFWfBBqNY9vAL3m3F+3uw==
dependencies:
es6-promise "^2.1.1"
lodash.assign "^2.4.1"
lodash.template "^2.4.1"
through2 "^2.0.0"
vinyl "^2.1.0"
gulp-if@^2.0.2: gulp-if@^2.0.2:
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-2.0.2.tgz#a497b7e7573005041caa2bc8b7dda3c80444d629" resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-2.0.2.tgz#a497b7e7573005041caa2bc8b7dda3c80444d629"
@ -7334,10 +7313,10 @@ gulp-merge-json@^1.3.1:
through "^2.3.8" through "^2.3.8"
vinyl "^2.1.0" vinyl "^2.1.0"
gulp-rename@^1.4.0: gulp-rename@^2.0.0:
version "1.4.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/gulp-rename/-/gulp-rename-1.4.0.tgz#de1c718e7c4095ae861f7296ef4f3248648240bd" resolved "https://registry.yarnpkg.com/gulp-rename/-/gulp-rename-2.0.0.tgz#9bbc3962b0c0f52fc67cd5eaff6c223ec5b9cf6c"
integrity sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg== integrity sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==
gulp-sourcemaps@1.6.0: gulp-sourcemaps@1.6.0:
version "1.6.0" version "1.6.0"
@ -8844,55 +8823,6 @@ locate-path@^3.0.0:
p-locate "^3.0.0" p-locate "^3.0.0"
path-exists "^3.0.0" path-exists "^3.0.0"
lodash._basebind@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash._basebind/-/lodash._basebind-2.4.1.tgz#e940b9ebdd27c327e0a8dab1b55916c5341e9575"
integrity sha1-6UC5690nwyfgqNqxtVkWxTQelXU=
dependencies:
lodash._basecreate "~2.4.1"
lodash._setbinddata "~2.4.1"
lodash._slice "~2.4.1"
lodash.isobject "~2.4.1"
lodash._basecreate@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-2.4.1.tgz#f8e6f5b578a9e34e541179b56b8eeebf4a287e08"
integrity sha1-+Ob1tXip405UEXm1a47uv0oofgg=
dependencies:
lodash._isnative "~2.4.1"
lodash.isobject "~2.4.1"
lodash.noop "~2.4.1"
lodash._basecreatecallback@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash._basecreatecallback/-/lodash._basecreatecallback-2.4.1.tgz#7d0b267649cb29e7a139d0103b7c11fae84e4851"
integrity sha1-fQsmdknLKeehOdAQO3wR+uhOSFE=
dependencies:
lodash._setbinddata "~2.4.1"
lodash.bind "~2.4.1"
lodash.identity "~2.4.1"
lodash.support "~2.4.1"
lodash._basecreatewrapper@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.4.1.tgz#4d31f2e7de7e134fbf2803762b8150b32519666f"
integrity sha1-TTHy595+E0+/KAN2K4FQsyUZZm8=
dependencies:
lodash._basecreate "~2.4.1"
lodash._setbinddata "~2.4.1"
lodash._slice "~2.4.1"
lodash.isobject "~2.4.1"
lodash._createwrapper@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash._createwrapper/-/lodash._createwrapper-2.4.1.tgz#51d6957973da4ed556e37290d8c1a18c53de1607"
integrity sha1-UdaVeXPaTtVW43KQ2MGhjFPeFgc=
dependencies:
lodash._basebind "~2.4.1"
lodash._basecreatewrapper "~2.4.1"
lodash._slice "~2.4.1"
lodash.isfunction "~2.4.1"
lodash._escapehtmlchar@~2.4.1: lodash._escapehtmlchar@~2.4.1:
version "2.4.1" version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz#df67c3bb6b7e8e1e831ab48bfa0795b92afe899d" resolved "https://registry.yarnpkg.com/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz#df67c3bb6b7e8e1e831ab48bfa0795b92afe899d"
@ -8938,14 +8868,6 @@ lodash._reunescapedhtml@~2.4.1:
lodash._htmlescapes "~2.4.1" lodash._htmlescapes "~2.4.1"
lodash.keys "~2.4.1" lodash.keys "~2.4.1"
lodash._setbinddata@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash._setbinddata/-/lodash._setbinddata-2.4.1.tgz#f7c200cd1b92ef236b399eecf73c648d17aa94d2"
integrity sha1-98IAzRuS7yNrOZ7s9zxkjReqlNI=
dependencies:
lodash._isnative "~2.4.1"
lodash.noop "~2.4.1"
lodash._shimkeys@~2.4.1: lodash._shimkeys@~2.4.1:
version "2.4.1" version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz#6e9cc9666ff081f0b5a6c978b83e242e6949d203" resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz#6e9cc9666ff081f0b5a6c978b83e242e6949d203"
@ -8953,28 +8875,6 @@ lodash._shimkeys@~2.4.1:
dependencies: dependencies:
lodash._objecttypes "~2.4.1" lodash._objecttypes "~2.4.1"
lodash._slice@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash._slice/-/lodash._slice-2.4.1.tgz#745cf41a53597b18f688898544405efa2b06d90f"
integrity sha1-dFz0GlNZexj2iImFREBe+isG2Q8=
lodash.assign@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-2.4.1.tgz#84c39596dd71181a97b0652913a7c9675e49b1aa"
integrity sha1-hMOVlt1xGBqXsGUpE6fJZ15Jsao=
dependencies:
lodash._basecreatecallback "~2.4.1"
lodash._objecttypes "~2.4.1"
lodash.keys "~2.4.1"
lodash.bind@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-2.4.1.tgz#5d19fa005c8c4d236faf4742c7b7a1fcabe29267"
integrity sha1-XRn6AFyMTSNvr0dCx7eh/Kvikmc=
dependencies:
lodash._createwrapper "~2.4.1"
lodash._slice "~2.4.1"
lodash.camelcase@^4.3.0: lodash.camelcase@^4.3.0:
version "4.3.0" version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
@ -9002,21 +8902,11 @@ lodash.escape@~2.4.1:
lodash._reunescapedhtml "~2.4.1" lodash._reunescapedhtml "~2.4.1"
lodash.keys "~2.4.1" lodash.keys "~2.4.1"
lodash.identity@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash.identity/-/lodash.identity-2.4.1.tgz#6694cffa65fef931f7c31ce86c74597cf560f4f1"
integrity sha1-ZpTP+mX++TH3wxzobHRZfPVg9PE=
lodash.isequal@^4.0.0: lodash.isequal@^4.0.0:
version "4.5.0" version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
lodash.isfunction@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-2.4.1.tgz#2cfd575c73e498ab57e319b77fa02adef13a94d1"
integrity sha1-LP1XXHPkmKtX4xm3f6Aq3vE6lNE=
lodash.isobject@~2.4.1: lodash.isobject@~2.4.1:
version "2.4.1" version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.4.1.tgz#5a2e47fe69953f1ee631a7eba1fe64d2d06558f5" resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.4.1.tgz#5a2e47fe69953f1ee631a7eba1fe64d2d06558f5"
@ -9043,11 +8933,6 @@ lodash.mergewith@^4.6.1:
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
lodash.noop@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-2.4.1.tgz#4fb54f816652e5ae10e8f72f717a388c7326538a"
integrity sha1-T7VPgWZS5a4Q6PcvcXo4jHMmU4o=
lodash.padend@^4.6.1: lodash.padend@^4.6.1:
version "4.6.1" version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e" resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e"
@ -9063,13 +8948,6 @@ lodash.sortby@^4.7.0:
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
lodash.support@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash.support/-/lodash.support-2.4.1.tgz#320e0b67031673c28d7a2bb5d9e0331a45240515"
integrity sha1-Mg4LZwMWc8KNeiu12eAzGkUkBRU=
dependencies:
lodash._isnative "~2.4.1"
lodash.template@^2.4.1: lodash.template@^2.4.1:
version "2.4.1" version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-2.4.1.tgz#9e611007edf629129a974ab3c48b817b3e1cf20d" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-2.4.1.tgz#9e611007edf629129a974ab3c48b817b3e1cf20d"
@ -13613,6 +13491,14 @@ verror@1.10.0:
core-util-is "1.0.2" core-util-is "1.0.2"
extsprintf "^1.2.0" extsprintf "^1.2.0"
vinyl-buffer@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/vinyl-buffer/-/vinyl-buffer-1.0.1.tgz#96c1a3479b8c5392542c612029013b5b27f88bbf"
integrity sha1-lsGjR5uMU5JULGEgKQE7Wyf4i78=
dependencies:
bl "^1.2.1"
through2 "^2.0.3"
vinyl-fs@^2.4.4: vinyl-fs@^2.4.4:
version "2.4.4" version "2.4.4"
resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239" resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239"
@ -13659,6 +13545,14 @@ vinyl-fs@^3.0.0:
vinyl "^2.0.0" vinyl "^2.0.0"
vinyl-sourcemap "^1.1.0" vinyl-sourcemap "^1.1.0"
vinyl-source-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/vinyl-source-stream/-/vinyl-source-stream-2.0.0.tgz#f38a5afb9dd1e93b65d550469ac6182ac4f54b8e"
integrity sha1-84pa+53R6Ttl1VBGmsYYKsT1S44=
dependencies:
through2 "^2.0.3"
vinyl "^2.1.0"
vinyl-sourcemap@^1.1.0: vinyl-sourcemap@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz#92a800593a38703a8cdb11d8b300ad4be63b3e16" resolved "https://registry.yarnpkg.com/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz#92a800593a38703a8cdb11d8b300ad4be63b3e16"