Use server side rendering in parse tests

Co-Authored-By: Richard Lewis <richrd@users.noreply.github.com>
This commit is contained in:
Pavel Djundik 2018-09-05 22:21:58 +03:00
parent 4f3dbc4b8f
commit 47b9924f26
4 changed files with 173 additions and 53 deletions

View file

@ -74,6 +74,8 @@
"@babel/preset-env": "7.3.1",
"@fortawesome/fontawesome-free": "5.7.1",
"babel-loader": "8.0.5",
"@vue/server-test-utils": "1.0.0-beta.27",
"@vue/test-utils": "1.0.0-beta.27",
"chai": "4.2.0",
"copy-webpack-plugin": "4.6.0",
"css-loader": "0.28.11",
@ -107,6 +109,7 @@
"undate": "0.3.0",
"vue": "2.5.17",
"vue-loader": "15.4.2",
"vue-server-renderer": "2.5.17",
"vue-template-compiler": "2.5.17",
"vuedraggable": "2.16.0",
"webpack": "4.29.3",

View file

@ -0,0 +1,24 @@
<template>
<div>
<ParsedMessage
:text="text"
:message="message"
:network="network" />
</div>
</template>
<script>
import ParsedMessage from "../../../client/components/ParsedMessage.vue";
export default {
name: "ParsedMessageTestWrapper",
components: {
ParsedMessage,
},
props: {
text: String,
message: Object,
network: Object,
},
};
</script>

View file

@ -1,19 +1,35 @@
"use strict";
const expect = require("chai").expect;
const parse = require("../../../../../client/js/libs/handlebars/parse");
import {renderToString} from "@vue/server-test-utils";
import ParsedMessageTestWrapper from "../../../components/ParsedMessageTestWrapper.vue";
function getParsedMessageContents(text, message) {
let contents = renderToString(ParsedMessageTestWrapper, {
propsData: {
text,
message,
},
});
// The wrapper adds a surrounding div to the message html, so we clean that out here
contents = contents.replace(/^<div data-server-rendered="true">([^]+)<\/div>$/m, "$1");
return contents;
}
describe("parse Handlebars helper", () => {
it("should not introduce xss", () => {
const testCases = [{
input: "<img onerror='location.href=\"//youtube.com\"'>",
expected: "&lt;img onerror&#x3D;&#x27;location.href&#x3D;&quot;<a href=\"http://youtube.com\" target=\"_blank\" rel=\"noopener\">//youtube.com</a>&quot;&#x27;&gt;",
expected: "&lt;img onerror='location.href=&quot;<a href=\"http://youtube.com\" target=\"_blank\" rel=\"noopener\">//youtube.com</a>&quot;'&gt;",
}, {
input: '#&">bug',
expected: '<span class="inline-channel" role="button" tabindex="0" data-chan="#&amp;&quot;&gt;bug">#&amp;&quot;&gt;bug</span>',
expected: '<span role="button" tabindex="0" data-chan="#&amp;&quot;&gt;bug" class="inline-channel">#&amp;&quot;&gt;bug</span>',
}];
const actual = testCases.map((testCase) => parse(testCase.input));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -25,7 +41,7 @@ describe("parse Handlebars helper", () => {
expected: '<span class="irc-underline irc-strikethrough irc-monospace">text\nwithcontrolcodestest</span>',
}];
const actual = testCases.map((testCase) => parse(testCase.input));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -68,7 +84,7 @@ describe("parse Handlebars helper", () => {
"</a>",
}];
const actual = testCases.map((testCase) => parse(testCase.input));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -79,11 +95,11 @@ describe("parse Handlebars helper", () => {
"bonuspunkt: your URL parser misparses this URL: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx";
const correctResult =
"bonuspunkt: your URL parser misparses this URL: " +
'<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v&#x3D;vs.85).aspx" target="_blank" rel="noopener">' +
"https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v&#x3D;vs.85).aspx" +
'<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx" target="_blank" rel="noopener">' +
"https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx" +
"</a>";
const actual = parse(input);
const actual = getParsedMessageContents(input);
expect(actual).to.deep.equal(correctResult);
});
@ -119,7 +135,7 @@ describe("parse Handlebars helper", () => {
"</a>",
}];
const actual = testCases.map((testCase) => parse(testCase.input));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -134,7 +150,7 @@ describe("parse Handlebars helper", () => {
expected: "http://.",
}];
const actual = testCases.map((testCase) => parse(testCase.input));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -144,45 +160,45 @@ describe("parse Handlebars helper", () => {
const testCases = [{
input: "#a",
expected:
'<span class="inline-channel" role="button" tabindex="0" data-chan="#a">' +
'<span role="button" tabindex="0" data-chan="#a" class="inline-channel">' +
"#a" +
"</span>",
}, {
input: "#test",
expected:
'<span class="inline-channel" role="button" tabindex="0" data-chan="#test">' +
'<span role="button" tabindex="0" data-chan="#test" class="inline-channel">' +
"#test" +
"</span>",
}, {
input: "#äöü",
expected:
'<span class="inline-channel" role="button" tabindex="0" data-chan="#äöü">' +
'<span role="button" tabindex="0" data-chan="#äöü" class="inline-channel">' +
"#äöü" +
"</span>",
}, {
input: "inline #channel text",
expected:
"inline " +
'<span class="inline-channel" role="button" tabindex="0" data-chan="#channel">' +
'<span role="button" tabindex="0" data-chan="#channel" class="inline-channel">' +
"#channel" +
"</span>" +
" text",
}, {
input: "#1,000",
expected:
'<span class="inline-channel" role="button" tabindex="0" data-chan="#1,000">' +
'<span role="button" tabindex="0" data-chan="#1,000" class="inline-channel">' +
"#1,000" +
"</span>",
}, {
input: "@#a",
expected:
"@" +
'<span class="inline-channel" role="button" tabindex="0" data-chan="#a">' +
'<span role="button" tabindex="0" data-chan="#a" class="inline-channel">' +
"#a" +
"</span>",
}];
const actual = testCases.map((testCase) => parse(testCase.input));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -197,7 +213,7 @@ describe("parse Handlebars helper", () => {
expected: "#",
}];
const actual = testCases.map((testCase) => parse(testCase.input));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -222,11 +238,11 @@ describe("parse Handlebars helper", () => {
}, {
name: "hex foreground color",
input: "\x04663399rebeccapurple",
expected: '<span style="color:#663399">rebeccapurple</span>',
expected: '<span style="color:#663399;">rebeccapurple</span>',
}, {
name: "hex foreground and background colors",
input: "\x04415364,ff9e18The Lounge",
expected: '<span style="color:#415364;background-color:#FF9E18">The Lounge</span>',
expected: '<span style="color:#415364;background-color:#FF9E18;">The Lounge</span>',
}, {
name: "italic",
input: "\x1ditalic",
@ -281,22 +297,24 @@ describe("parse Handlebars helper", () => {
'<span class="irc-bold">bold</span>',
}].forEach((item) => { // TODO: In Node v6+, use `{name, input, expected}`
it(`should handle style characters: ${item.name}`, function() {
expect(parse(item.input)).to.equal(item.expected);
expect(getParsedMessageContents(item.input)).to.equal(item.expected);
});
});
it("should find nicks", () => {
const testCases = [{
users: ["MaxLeiter"],
message: {
users: ["MaxLeiter"],
},
input: "test, MaxLeiter",
expected:
"test, " +
'<span role="button" class="user color-12" data-name="MaxLeiter">' +
'<span role="button" data-name="MaxLeiter" class="user color-12">' +
"MaxLeiter" +
"</span>",
}];
const actual = testCases.map((testCase) => parse(testCase.input, testCase.users));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input, testCase.message));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -307,7 +325,7 @@ describe("parse Handlebars helper", () => {
users: ["MaxLeiter, test"],
input: "#test-channelMaxLeiter",
expected:
'<span class="inline-channel" role="button" tabindex="0" data-chan="#test-channelMaxLeiter">' +
'<span role="button" tabindex="0" data-chan="#test-channelMaxLeiter" class="inline-channel">' +
"#test-channelMaxLeiter" +
"</span>",
},
@ -322,7 +340,7 @@ describe("parse Handlebars helper", () => {
];
const actual = testCases.map((testCase) => parse(testCase.input));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -342,13 +360,13 @@ describe("parse Handlebars helper", () => {
}, {
input: "\x02#\x038,9thelounge",
expected:
'<span class="inline-channel" role="button" tabindex="0" data-chan="#thelounge">' +
'<span role="button" tabindex="0" data-chan="#thelounge" class="inline-channel">' +
'<span class="irc-bold">#</span>' +
'<span class="irc-bold irc-fg8 irc-bg9">thelounge</span>' +
"</span>",
}];
const actual = testCases.map((testCase) => parse(testCase.input));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -358,20 +376,20 @@ describe("parse Handlebars helper", () => {
[{
name: "in text",
input: "Hello💬",
expected: 'Hello<span class="emoji" role="img" aria-label="Emoji: speech balloon" title="speech balloon">💬</span>',
expected: 'Hello<span role="img" aria-label="Emoji: speech balloon" title="Emoji: speech balloon" class="emoji">💬</span>',
}, {
name: "complicated zero-join-width emoji",
input: "🤦🏿‍♀️",
expected: '<span class="emoji" role="img" aria-label="Emoji: woman facepalming: dark skin tone" title="woman facepalming: dark skin tone">🤦🏿‍♀️</span>',
expected: '<span role="img" aria-label="Emoji: woman facepalming: dark skin tone" title="Emoji: woman facepalming: dark skin tone" class="emoji">🤦🏿‍♀️</span>',
}, {
name: "with modifiers",
input: "🤷‍♀️",
expected: '<span class="emoji" role="img" aria-label="Emoji: woman shrugging" title="woman shrugging">🤷‍♀️</span>',
expected: '<span role="img" aria-label="Emoji: woman shrugging" title="Emoji: woman shrugging" class="emoji">🤷‍♀️</span>',
}, {
// FIXME: These multiple `span`s should be optimized into a single one. See https://github.com/thelounge/thelounge/issues/1783
name: "wrapped in style",
input: "Super \x034💚 green!",
expected: 'Super <span class="emoji" role="img" aria-label="Emoji: green heart" title="green heart"><span class="irc-fg4">💚</span></span><span class="irc-fg4"> green!</span>',
expected: 'Super <span role="img" aria-label="Emoji: green heart" title="Emoji: green heart" class="emoji"><span class="irc-fg4">💚</span></span><span class="irc-fg4"> green!</span>',
}, {
name: "wrapped in URLs",
input: "https://i.❤️.thelounge.chat",
@ -381,10 +399,10 @@ describe("parse Handlebars helper", () => {
name: "wrapped in channels",
input: "#i❤thelounge",
// FIXME: Emoji in text should be `<span class="emoji">❤️</span>`. See https://github.com/thelounge/thelounge/issues/1784
expected: '<span class="inline-channel" role="button" tabindex="0" data-chan="#i❤thelounge">#i❤thelounge</span>',
expected: '<span role="button" tabindex="0" data-chan="#i❤thelounge" class="inline-channel">#i❤thelounge</span>',
}].forEach((item) => { // TODO: In Node v6+, use `{name, input, expected}`
it(`should find emoji: ${item.name}`, function() {
expect(parse(item.input)).to.equal(item.expected);
expect(getParsedMessageContents(item.input)).to.equal(item.expected);
});
});
@ -393,12 +411,12 @@ describe("parse Handlebars helper", () => {
input: 'test \x0312#\x0312\x0312"te\x0312st\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312a',
expected:
"test " +
'<span class="inline-channel" role="button" tabindex="0" data-chan="#&quot;testa">' +
'<span role="button" tabindex="0" data-chan="#&quot;testa" class="inline-channel">' +
'<span class="irc-fg12">#&quot;testa</span>' +
"</span>",
}];
const actual = testCases.map((testCase) => parse(testCase.input));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -421,7 +439,7 @@ describe("parse Handlebars helper", () => {
"</a>",
}];
const actual = testCases.map((testCase) => parse(testCase.input));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -436,7 +454,7 @@ describe("parse Handlebars helper", () => {
"</a>",
}];
const actual = testCases.map((testCase) => parse(testCase.input));
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
const expected = testCases.map((testCase) => testCase.expected);
expect(actual).to.deep.equal(expected);
@ -444,20 +462,20 @@ describe("parse Handlebars helper", () => {
it("should not overlap parts", () => {
const input = "Url: http://example.com/path Channel: ##channel";
const actual = parse(input);
const actual = getParsedMessageContents(input);
expect(actual).to.equal(
'Url: <a href="http://example.com/path" target="_blank" rel="noopener">http://example.com/path</a> ' +
'Channel: <span class="inline-channel" role="button" tabindex="0" data-chan="##channel">##channel</span>'
'Channel: <span role="button" tabindex="0" data-chan="##channel" class="inline-channel">##channel</span>'
);
});
it("should handle overlapping parts by using first starting", () => {
const input = "#test-https://example.com";
const actual = parse(input);
const actual = getParsedMessageContents(input);
expect(actual).to.equal(
'<span class="inline-channel" role="button" tabindex="0" data-chan="#test-https://example.com">' +
'<span role="button" tabindex="0" data-chan="#test-https://example.com" class="inline-channel">' +
"#test-https://example.com" +
"</span>"
);

View file

@ -572,8 +572,8 @@
defer-to-connect "^1.0.1"
"@types/node@*":
version "10.12.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
version "10.9.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.9.4.tgz#0f4cb2dc7c1de6096055357f70179043c33e9897"
"@types/unist@*", "@types/unist@^2.0.0":
version "2.0.2"
@ -608,6 +608,21 @@
source-map "^0.5.6"
vue-template-es2015-compiler "^1.6.0"
"@vue/server-test-utils@1.0.0-beta.27":
version "1.0.0-beta.27"
resolved "https://registry.yarnpkg.com/@vue/server-test-utils/-/server-test-utils-1.0.0-beta.27.tgz#0c61cb724d04bf44c70938b4a6054e73e914492a"
integrity sha512-HKwm1Nw180qNgknPyok/XWJF4ojBZC5vSANPf+f1WR2jYsSc0vvAxUyX2Qeq4F7KLXrfsFwdkfH3a5BxdrA9tg==
dependencies:
cheerio "^1.0.0-rc.2"
"@vue/test-utils@1.0.0-beta.27":
version "1.0.0-beta.27"
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.0.0-beta.27.tgz#7e5f7b7180c00e28a4ca55c0ff0a7e754377fdb2"
integrity sha512-Lzrd4ZBkS70Tl8JbXbDrN/NcSaH9aZT6+7emU3QhTJ+CrorJpyFDA1dkvSIhH+rDTs8sHFbGeXjXV/qorXxtRw==
dependencies:
dom-event-types "^1.0.0"
lodash "^4.17.4"
"@webassemblyjs/ast@1.7.11":
version "1.7.11"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz#b988582cafbb2b095e8b556526f30c90d057cace"
@ -1614,6 +1629,17 @@ cheerio@0.22.0:
lodash.reject "^4.4.0"
lodash.some "^4.4.0"
cheerio@^1.0.0-rc.2:
version "1.0.0-rc.2"
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db"
dependencies:
css-select "~1.2.0"
dom-serializer "~0.1.0"
entities "~1.1.1"
htmlparser2 "^3.9.1"
lodash "^4.15.0"
parse5 "^3.0.1"
chokidar@^2.0.0, chokidar@^2.0.2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26"
@ -2365,6 +2391,11 @@ doctrine@^2.1.0:
dependencies:
esutils "^2.0.2"
dom-event-types@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dom-event-types/-/dom-event-types-1.0.0.tgz#5830a0a29e1bf837fe50a70cd80a597232813cae"
integrity sha512-2G2Vwi2zXTHBGqXHsJ4+ak/iP0N8Ar+G8a7LiD2oup5o4sQWytwqqrZu/O6hIMV0KMID2PL69OhpshLO0n7UJQ==
dom-serializer@0, dom-serializer@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
@ -4363,6 +4394,10 @@ locate-path@^3.0.0:
p-locate "^3.0.0"
path-exists "^3.0.0"
lodash._reinterpolate@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
lodash.assignin@^4.0.9:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2"
@ -4431,14 +4466,31 @@ lodash.some@^4.4.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
lodash.template@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
dependencies:
lodash._reinterpolate "~3.0.0"
lodash.templatesettings "^4.0.0"
lodash.templatesettings@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316"
dependencies:
lodash._reinterpolate "~3.0.0"
lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
lodash@4.17.11, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0:
lodash@4.17.11, lodash@^4.17.11:
version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0:
version "4.17.10"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
log-symbols@^2.0.0, log-symbols@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
@ -5392,6 +5444,12 @@ parse-passwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
parse5@^3.0.1:
version "3.0.3"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
dependencies:
"@types/node" "*"
parseqs@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
@ -6350,11 +6408,11 @@ resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
resolve@^1.3.2:
version "1.10.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba"
resolve@^1.2.0, resolve@^1.3.2:
version "1.8.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26"
dependencies:
path-parse "^1.0.6"
path-parse "^1.0.5"
responselike@^1.0.2:
version "1.0.2"
@ -6485,9 +6543,9 @@ send@0.16.2:
range-parser "~1.2.0"
statuses "~1.4.0"
serialize-javascript@^1.4.0:
version "1.6.1"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.6.1.tgz#4d1f697ec49429a847ca6f442a2a755126c4d879"
serialize-javascript@^1.3.0, serialize-javascript@^1.4.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe"
serve-index@^1.7.2:
version "1.9.1"
@ -6730,6 +6788,10 @@ source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
source-map@0.5.6:
version "0.5.6"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
@ -7649,6 +7711,19 @@ vue-loader@15.4.2:
vue-hot-reload-api "^2.3.0"
vue-style-loader "^4.1.0"
vue-server-renderer@2.5.17:
version "2.5.17"
resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.5.17.tgz#c1f24815a4b12a2797c154549b29b44b6be004b5"
dependencies:
chalk "^1.1.3"
hash-sum "^1.0.2"
he "^1.1.0"
lodash.template "^4.4.0"
lodash.uniq "^4.5.0"
resolve "^1.2.0"
serialize-javascript "^1.3.0"
source-map "0.5.6"
vue-style-loader@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.0.tgz#7588bd778e2c9f8d87bfc3c5a4a039638da7a863"