diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt
index 1ca7809193..c3b2fa83aa 100644
--- a/ThirdPartyNotices.txt
+++ b/ThirdPartyNotices.txt
@@ -34,6 +34,7 @@ expressly granted herein, whether by implication, estoppel or otherwise.
jquery-ui: https://github.com/jquery/jquery-ui
jquery.event.drag: https://github.com/devongovett/jquery.event.drag
jschardet: https://github.com/aadsm/jschardet
+ JupyterLab: https://github.com/jupyterlab/jupyterlab
make-error: https://github.com/JsCommunity/make-error
minimist: https://github.com/substack/minimist
moment: https://github.com/moment/moment
@@ -1166,6 +1167,43 @@ That's all there is to it!
=========================================
END OF jschardet NOTICES AND INFORMATION
+%% JupyterLab NOTICES AND INFORMATION BEGIN HERE
+Copyright (c) 2015 Project Jupyter Contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Semver File License
+===================
+
+The semver.py file is from https://github.com/podhmo/python-semver
+which is licensed under the "MIT" license. See the semver.py file for details.
+
+END OF JupyterLab NOTICES AND INFORMATION
+
%% make-error NOTICES AND INFORMATION BEGIN HERE
=========================================
ISC © Julien Fontanet
diff --git a/build/yarn.lock b/build/yarn.lock
index 7e5ce01e6b..c92047d496 100644
--- a/build/yarn.lock
+++ b/build/yarn.lock
@@ -46,6 +46,7 @@
"@types/minimatch@^3.0.3":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
+ integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/node@*":
version "8.0.51"
diff --git a/extensions/azurecore/yarn.lock b/extensions/azurecore/yarn.lock
index 2ebfde1b74..4483da3cf8 100644
--- a/extensions/azurecore/yarn.lock
+++ b/extensions/azurecore/yarn.lock
@@ -10,6 +10,7 @@
"@types/node@^8.0.24":
version "8.10.36"
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.36.tgz#eac05d576fbcd0b4ea3c912dc58c20475c08d9e4"
+ integrity sha512-SL6KhfM7PTqiFmbCW3eVNwVBZ+88Mrzbuvn9olPsfv43mbiWaFY+nRcz/TGGku0/lc2FepdMbImdMY1JrQ+zbw==
"@types/node@^8.0.47":
version "8.10.30"
@@ -44,14 +45,17 @@ ajv@^5.3.0:
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+ integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+ integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
asn1@0.1.11:
version "0.1.11"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7"
+ integrity sha1-VZvhg3bQik7E2+gId9J4GGObLfc=
asn1@~0.2.3:
version "0.2.4"
@@ -68,6 +72,7 @@ assert-plus@1.0.0, assert-plus@^1.0.0:
assert-plus@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160"
+ integrity sha1-7nQAlBMALYTOxyGcasgRgS5yMWA=
async@2.6.0:
version "2.6.0"
@@ -79,6 +84,7 @@ async@2.6.0:
async@>=0.6.0, async@^2.0.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
+ integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==
dependencies:
lodash "^4.17.10"
@@ -90,6 +96,7 @@ asynckit@^0.4.0:
aws-sign2@~0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63"
+ integrity sha1-xXED96F/wDfwLXwuZLYC6iI/fWM=
aws-sign2@~0.7.0:
version "0.7.0"
@@ -132,16 +139,19 @@ bcrypt-pbkdf@^1.0.0:
bl@~1.0.0:
version "1.0.3"
resolved "http://registry.npmjs.org/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e"
+ integrity sha1-/FQhoo/UImA2w7OJGmaiW8ZNIm4=
dependencies:
readable-stream "~2.0.5"
bluebird@^2.9.30:
version "2.11.0"
resolved "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
+ integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=
boom@2.x.x:
version "2.10.1"
resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+ integrity sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=
dependencies:
hoek "2.x.x"
@@ -166,6 +176,7 @@ buffer-equal-constant-time@1.0.1:
caseless@~0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
+ integrity sha1-cVuW6phBWTzDMGeSP17GDr2k99c=
caseless@~0.12.0:
version "0.12.0"
@@ -175,6 +186,7 @@ caseless@~0.12.0:
chalk@^1.0.0:
version "1.1.3"
resolved "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+ integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
dependencies:
ansi-styles "^2.2.1"
escape-string-regexp "^1.0.2"
@@ -202,6 +214,7 @@ combined-stream@1.0.6:
combined-stream@^1.0.5, combined-stream@~1.0.1, combined-stream@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
+ integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==
dependencies:
delayed-stream "~1.0.0"
@@ -213,6 +226,7 @@ commander@2.15.1:
commander@^2.8.1:
version "2.19.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
+ integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
concat-map@0.0.1:
version "0.0.1"
@@ -222,16 +236,19 @@ concat-map@0.0.1:
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+ integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
cryptiles@2.x.x:
version "2.0.5"
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+ integrity sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=
dependencies:
boom "2.x.x"
ctype@0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f"
+ integrity sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8=
dashdash@^1.12.0:
version "1.14.1"
@@ -285,10 +302,12 @@ ecdsa-sig-formatter@1.0.10:
escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
extend@~3.0.0, extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+ integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
extsprintf@1.3.0:
version "1.3.0"
@@ -313,10 +332,12 @@ fast-json-stable-stringify@^2.0.0:
forever-agent@~0.6.0, forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+ integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
form-data@~1.0.0-rc1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c"
+ integrity sha1-rjFduaSQf6BlUCMEpm13M0de43w=
dependencies:
async "^2.0.1"
combined-stream "^1.0.5"
@@ -339,12 +360,14 @@ fs.realpath@^1.0.0:
generate-function@^2.0.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f"
+ integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==
dependencies:
is-property "^1.0.2"
generate-object-property@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0"
+ integrity sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=
dependencies:
is-property "^1.0.0"
@@ -380,6 +403,7 @@ har-schema@^2.0.0:
har-validator@^1.6.1:
version "1.8.0"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-1.8.0.tgz#d83842b0eb4c435960aeb108a067a3aa94c0eeb2"
+ integrity sha1-2DhCsOtMQ1lgrrEIoGejqpTA7rI=
dependencies:
bluebird "^2.9.30"
chalk "^1.0.0"
@@ -397,6 +421,7 @@ har-validator@~5.1.0:
has-ansi@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+ integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
dependencies:
ansi-regex "^2.0.0"
@@ -408,6 +433,7 @@ has-flag@^3.0.0:
hawk@~3.1.0:
version "3.1.3"
resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+ integrity sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=
dependencies:
boom "2.x.x"
cryptiles "2.x.x"
@@ -422,10 +448,12 @@ he@1.1.1:
hoek@2.x.x:
version "2.16.3"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+ integrity sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=
http-signature@~0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.11.0.tgz#1796cf67a001ad5cd6849dca0991485f09089fe6"
+ integrity sha1-F5bPZ6ABrVzWhJ3KCZFIXwkIn+Y=
dependencies:
asn1 "0.1.11"
assert-plus "^0.1.5"
@@ -451,6 +479,7 @@ inflight@^1.0.4:
inherits@2, inherits@~2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+ integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
is-buffer@^1.1.6:
version "1.1.6"
@@ -460,10 +489,12 @@ is-buffer@^1.1.6:
is-my-ip-valid@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824"
+ integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==
is-my-json-valid@^2.12.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175"
+ integrity sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q==
dependencies:
generate-function "^2.0.0"
generate-object-property "^1.1.0"
@@ -474,6 +505,7 @@ is-my-json-valid@^2.12.0:
is-property@^1.0.0, is-property@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
+ integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=
is-stream@^1.1.0:
version "1.1.0"
@@ -488,10 +520,12 @@ is-typedarray@~1.0.0:
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+ integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
isstream@~0.1.1, isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+ integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
jsbn@~0.1.0:
version "0.1.1"
@@ -511,10 +545,12 @@ json-schema@0.2.3:
json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+ integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
jsonpointer@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9"
+ integrity sha1-T9kss04OnbPInIYi7PUfm5eMbLk=
jsprim@^1.2.2:
version "1.4.1"
@@ -556,6 +592,7 @@ mime-db@~1.36.0:
mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.2:
version "2.1.20"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19"
+ integrity sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==
dependencies:
mime-db "~1.36.0"
@@ -634,10 +671,12 @@ ms@2.0.0:
node-uuid@~1.4.0:
version "1.4.8"
resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907"
+ integrity sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=
oauth-sign@~0.8.0:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+ integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=
oauth-sign@~0.9.0:
version "0.9.0"
@@ -669,6 +708,7 @@ postinstall-build@^5.0.1:
process-nextick-args@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+ integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=
psl@^1.1.24:
version "1.1.29"
@@ -683,6 +723,7 @@ punycode@^1.4.1:
qs@~5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-5.1.0.tgz#4d932e5c7ea411cca76a312d39a606200fd50cd9"
+ integrity sha1-TZMuXH6kEcynajEtOaYGIA/VDNk=
qs@~6.5.2:
version "6.5.2"
@@ -692,6 +733,7 @@ qs@~6.5.2:
readable-stream@~2.0.5:
version "2.0.6"
resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
+ integrity sha1-j5A0HmilPMySh4jaz80Rs265t44=
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.1"
@@ -703,6 +745,7 @@ readable-stream@~2.0.5:
request@2.63.0:
version "2.63.0"
resolved "http://registry.npmjs.org/request/-/request-2.63.0.tgz#c83e7c3485e5d9bf9b146318429bc48f1253d8be"
+ integrity sha1-yD58NIXl2b+bFGMYQpvEjxJT2L4=
dependencies:
aws-sign2 "~0.5.0"
bl "~1.0.0"
@@ -807,6 +850,7 @@ should@^13.2.1:
sntp@1.x.x:
version "1.0.9"
resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+ integrity sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=
dependencies:
hoek "2.x.x"
@@ -829,14 +873,17 @@ sshpk@^1.7.0:
string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+ integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
stringstream@~0.0.4:
version "0.0.6"
resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72"
+ integrity sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==
strip-ansi@^3.0.0:
version "3.0.1"
resolved "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
dependencies:
ansi-regex "^2.0.0"
@@ -850,6 +897,7 @@ supports-color@5.4.0:
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+ integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
through@^2.3.8:
version "2.3.8"
@@ -859,6 +907,7 @@ through@^2.3.8:
tough-cookie@>=0.12.0, tough-cookie@~2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
+ integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
dependencies:
psl "^1.1.24"
punycode "^1.4.1"
@@ -873,6 +922,7 @@ tunnel-agent@^0.6.0:
tunnel-agent@~0.4.0:
version "0.4.3"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb"
+ integrity sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=
tunnel@0.0.5:
version "0.0.5"
@@ -901,6 +951,7 @@ typemoq@^2.1.0:
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
uuid@^3.1.0, uuid@^3.2.1, uuid@^3.3.2:
version "3.3.2"
@@ -934,7 +985,9 @@ wrappy@1:
xpath.js@~1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/xpath.js/-/xpath.js-1.1.0.tgz#3816a44ed4bb352091083d002a383dd5104a5ff1"
+ integrity sha512-jg+qkfS4K8E7965sqaUl8mRngXiKb3WZGfONgE18pr03FUQiuSV6G+Ej4tS55B+rIQSFEIw3phdVAQ4pPqNWfQ==
xtend@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+ integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
diff --git a/extensions/import/yarn.lock b/extensions/import/yarn.lock
index 3dc0f8a91b..b1e352edce 100644
--- a/extensions/import/yarn.lock
+++ b/extensions/import/yarn.lock
@@ -12,6 +12,7 @@ agent-base@4, agent-base@^4.1.0:
applicationinsights@1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/applicationinsights/-/applicationinsights-1.0.1.tgz#53446b830fe8d5d619eee2a278b31d3d25030927"
+ integrity sha1-U0Rrgw/o1dYZ7uKieLMdPSUDCSc=
dependencies:
diagnostic-channel "0.2.0"
diagnostic-channel-publishers "0.2.1"
@@ -143,10 +144,12 @@ decompress@^4.2.0:
diagnostic-channel-publishers@0.2.1:
version "0.2.1"
resolved "https://registry.npmjs.org/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
+ integrity sha1-ji1geottef6IC1SLxYzGvrKIxPM=
diagnostic-channel@0.2.0:
version "0.2.0"
resolved "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17"
+ integrity sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc=
dependencies:
semver "^5.3.0"
@@ -366,6 +369,7 @@ seek-bzip@^1.0.5:
semver@^5.3.0:
version "5.6.0"
resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
+ integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
"service-downloader@github:anthonydresser/service-downloader#0.1.5":
version "0.1.5"
@@ -438,6 +442,7 @@ util-deprecate@~1.0.1:
vscode-extension-telemetry@0.0.18:
version "0.0.18"
resolved "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.18.tgz#602ba20d8c71453aa34533a291e7638f6e5c0327"
+ integrity sha512-Vw3Sr+dZwl+c6PlsUwrTtCOJkgrmvS3OUVDQGcmpXWAgq9xGq6as0K4pUx+aGqTjzLAESmWSrs6HlJm6J6Khcg==
dependencies:
applicationinsights "1.0.1"
@@ -492,3 +497,4 @@ yauzl@^2.4.2:
zone.js@0.7.6:
version "0.7.6"
resolved "https://registry.npmjs.org/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
+ integrity sha1-+7w50+AmHQmG8boGMG6zrrDSIAk=
diff --git a/package.json b/package.json
index 3abb6216c7..1a05cc19af 100644
--- a/package.json
+++ b/package.json
@@ -37,8 +37,10 @@
"@angular/router": "~4.1.3",
"@angular/upgrade": "~4.1.3",
"@types/chart.js": "^2.7.31",
+ "@types/htmlparser2": "^3.7.31",
"angular2-grid": "2.0.6",
"angular2-slickgrid": "github:Microsoft/angular2-slickgrid#1.4.6",
+ "ansi_up": "^3.0.0",
"applicationinsights": "0.18.0",
"chart.js": "^2.6.0",
"fast-plist": "0.1.2",
@@ -64,6 +66,7 @@
"pretty-data": "^0.40.0",
"reflect-metadata": "^0.1.8",
"rxjs": "5.4.0",
+ "sanitize-html": "^1.19.1",
"semver": "^5.5.0",
"slickgrid": "github:anthonydresser/SlickGrid#2.3.28",
"spdlog": "0.7.1",
@@ -85,6 +88,7 @@
"@types/keytar": "4.0.1",
"@types/minimist": "1.2.0",
"@types/mocha": "2.2.39",
+ "@types/sanitize-html": "^1.18.2",
"@types/semver": "5.3.30",
"@types/sinon": "1.16.34",
"@types/winreg": "^1.2.30",
diff --git a/src/sql/parts/notebook/cellViews/code.component.ts b/src/sql/parts/notebook/cellViews/code.component.ts
index 462798818c..9b3c270ae7 100644
--- a/src/sql/parts/notebook/cellViews/code.component.ts
+++ b/src/sql/parts/notebook/cellViews/code.component.ts
@@ -8,8 +8,6 @@ import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetecto
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
import { AngularDisposable } from 'sql/base/common/lifecycle';
-import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
-import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
import { QueryTextEditor } from 'sql/parts/modelComponents/queryTextEditor';
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
diff --git a/src/sql/parts/notebook/cellViews/codeCell.component.html b/src/sql/parts/notebook/cellViews/codeCell.component.html
index b7f97fed40..1351e5ef2f 100644
--- a/src/sql/parts/notebook/cellViews/codeCell.component.html
+++ b/src/sql/parts/notebook/cellViews/codeCell.component.html
@@ -8,7 +8,8 @@
-
- Place Holder for output area
+
+ 0" [cellModel]="cellModel">
+
-
+
\ No newline at end of file
diff --git a/src/sql/parts/notebook/cellViews/codeCell.component.ts b/src/sql/parts/notebook/cellViews/codeCell.component.ts
index 5e02d19dc7..c15f3cc42d 100644
--- a/src/sql/parts/notebook/cellViews/codeCell.component.ts
+++ b/src/sql/parts/notebook/cellViews/codeCell.component.ts
@@ -21,10 +21,8 @@ export const CODE_SELECTOR: string = 'code-cell-component';
templateUrl: decodeURI(require.toUrl('./codeCell.component.html'))
})
export class CodeCellComponent extends CellView implements OnInit {
- @ViewChild('output', { read: ElementRef }) private output: ElementRef;
@Input() cellModel: ICellModel;
constructor(
- @Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService
) {
@@ -42,7 +40,5 @@ export class CodeCellComponent extends CellView implements OnInit {
}
private updateTheme(theme: IColorTheme): void {
- let outputElement = this.output.nativeElement;
- outputElement.style.borderTopColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
}
}
diff --git a/src/sql/parts/notebook/cellViews/interfaces.ts b/src/sql/parts/notebook/cellViews/interfaces.ts
index dcf46d6887..1f188b6663 100644
--- a/src/sql/parts/notebook/cellViews/interfaces.ts
+++ b/src/sql/parts/notebook/cellViews/interfaces.ts
@@ -13,3 +13,5 @@ export abstract class CellView extends AngularDisposable implements OnDestroy {
public abstract layout(): void;
}
+
+
diff --git a/src/sql/parts/notebook/cellViews/output.component.html b/src/sql/parts/notebook/cellViews/output.component.html
new file mode 100644
index 0000000000..f05a51ae65
--- /dev/null
+++ b/src/sql/parts/notebook/cellViews/output.component.html
@@ -0,0 +1,11 @@
+
+
diff --git a/src/sql/parts/notebook/cellViews/output.component.ts b/src/sql/parts/notebook/cellViews/output.component.ts
new file mode 100644
index 0000000000..c3f8e9d4fe
--- /dev/null
+++ b/src/sql/parts/notebook/cellViews/output.component.ts
@@ -0,0 +1,77 @@
+/*---------------------------------------------------------------------------------------------
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Licensed under the Source EULA. See License.txt in the project root for license information.
+*--------------------------------------------------------------------------------------------*/
+import 'vs/css!./code';
+
+import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, Output, EventEmitter } from '@angular/core';
+import { AngularDisposable } from 'sql/base/common/lifecycle';
+import { nb } from 'sqlops';
+import { INotebookService } from 'sql/services/notebook/notebookService';
+import { MimeModel } from 'sql/parts/notebook/outputs/common/mimemodel';
+import * as outputProcessor from '../outputs/common/outputProcessor';
+import { RenderMimeRegistry } from 'sql/parts/notebook/outputs/registry';
+import 'vs/css!sql/parts/notebook/outputs/style/index';
+
+export const OUTPUT_SELECTOR: string = 'output-component';
+
+@Component({
+ selector: OUTPUT_SELECTOR,
+ templateUrl: decodeURI(require.toUrl('./output.component.html'))
+})
+export class OutputComponent extends AngularDisposable implements OnInit {
+ @ViewChild('output', { read: ElementRef }) private outputElement: ElementRef;
+ @Input() cellOutput: nb.ICellOutput;
+ private readonly _minimumHeight = 30;
+ registry: RenderMimeRegistry;
+ trusted: boolean = false;
+
+
+ constructor(
+ @Inject(INotebookService) private _notebookService: INotebookService
+ ) {
+ super();
+ this.registry = _notebookService.getMimeRegistry();
+ }
+
+ ngOnInit() {
+ let node = this.outputElement.nativeElement;
+ let output = this.cellOutput;
+ let options = outputProcessor.getBundleOptions({ value: output, trusted: this.trusted });
+ // TODO handle safe/unsafe mapping
+ this.createRenderedMimetype(options, node);
+ }
+
+ public layout(): void {
+ }
+
+ protected createRenderedMimetype(options: MimeModel.IOptions, node: HTMLElement): void {
+ let mimeType = this.registry.preferredMimeType(
+ options.data,
+ options.trusted ? 'any' : 'ensure'
+ );
+ if (mimeType) {
+ let output = this.registry.createRenderer(mimeType);
+ output.node = node;
+ let model = new MimeModel(options);
+ output.renderModel(model).catch(error => {
+ // Manually append error message to output
+ output.node.innerHTML = `Javascript Error: ${error.message}`;
+ // Remove mime-type-specific CSS classes
+ output.node.className = 'p-Widget jp-RenderedText';
+ output.node.setAttribute(
+ 'data-mime-type',
+ 'application/vnd.jupyter.stderr'
+ );
+ });
+ //this.setState({ node: node });
+ } else {
+ // TODO Localize
+ node.innerHTML =
+ `No ${options.trusted ? '' : '(safe) '}renderer could be ` +
+ 'found for output. It has the following MIME types: ' +
+ Object.keys(options.data).join(', ');
+ //this.setState({ node: node });
+ }
+ }
+}
diff --git a/src/sql/parts/notebook/cellViews/outputArea.component.html b/src/sql/parts/notebook/cellViews/outputArea.component.html
new file mode 100644
index 0000000000..15c0fe1f71
--- /dev/null
+++ b/src/sql/parts/notebook/cellViews/outputArea.component.html
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/src/sql/parts/notebook/cellViews/outputArea.component.ts b/src/sql/parts/notebook/cellViews/outputArea.component.ts
new file mode 100644
index 0000000000..461de0da21
--- /dev/null
+++ b/src/sql/parts/notebook/cellViews/outputArea.component.ts
@@ -0,0 +1,30 @@
+/*---------------------------------------------------------------------------------------------
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Licensed under the Source EULA. See License.txt in the project root for license information.
+*--------------------------------------------------------------------------------------------*/
+import 'vs/css!./code';
+import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, Output, EventEmitter } from '@angular/core';
+import { AngularDisposable } from 'sql/base/common/lifecycle';
+import { IModeService } from 'vs/editor/common/services/modeService';
+import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
+
+export const OUTPUT_AREA_SELECTOR: string = 'output-area-component';
+
+@Component({
+ selector: OUTPUT_AREA_SELECTOR,
+ templateUrl: decodeURI(require.toUrl('./outputArea.component.html'))
+})
+export class OutputAreaComponent extends AngularDisposable implements OnInit {
+ @Input() cellModel: ICellModel;
+
+ private readonly _minimumHeight = 30;
+
+ constructor(
+ @Inject(IModeService) private _modeService: IModeService
+ ) {
+ super();
+ }
+ ngOnInit(): void {
+
+ }
+}
diff --git a/src/sql/parts/notebook/models/modelInterfaces.ts b/src/sql/parts/notebook/models/modelInterfaces.ts
index ddd75c4179..50caeb3e76 100644
--- a/src/sql/parts/notebook/models/modelInterfaces.ts
+++ b/src/sql/parts/notebook/models/modelInterfaces.ts
@@ -338,6 +338,7 @@ export interface ICellModel {
cellType: CellType;
trustedMode: boolean;
active: boolean;
+ readonly outputs: ReadonlyArray;
equals(cellModel: ICellModel): boolean;
toJSON(): nb.ICell;
}
diff --git a/src/sql/parts/notebook/notebook.module.ts b/src/sql/parts/notebook/notebook.module.ts
index 2c5964b99d..d60a84edbe 100644
--- a/src/sql/parts/notebook/notebook.module.ts
+++ b/src/sql/parts/notebook/notebook.module.ts
@@ -26,6 +26,8 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { CodeComponent } from 'sql/parts/notebook/cellViews/code.component';
import { CodeCellComponent } from 'sql/parts/notebook/cellViews/codeCell.component';
import { TextCellComponent } from 'sql/parts/notebook/cellViews/textCell.component';
+import { OutputAreaComponent } from 'sql/parts/notebook/cellViews/outputArea.component';
+import { OutputComponent } from 'sql/parts/notebook/cellViews/output.component';
import LoadingSpinner from 'sql/parts/modelComponents/loadingSpinner.component';
export const NotebookModule = (params, selector: string, instantiationService: IInstantiationService): any => {
@@ -40,7 +42,9 @@ export const NotebookModule = (params, selector: string, instantiationService: I
CodeCellComponent,
TextCellComponent,
NotebookComponent,
- ComponentHostDirective
+ ComponentHostDirective,
+ OutputAreaComponent,
+ OutputComponent
],
entryComponents: [NotebookComponent],
imports: [
diff --git a/src/sql/parts/notebook/outputs/common/jsonext.ts b/src/sql/parts/notebook/outputs/common/jsonext.ts
new file mode 100644
index 0000000000..95de8717f1
--- /dev/null
+++ b/src/sql/parts/notebook/outputs/common/jsonext.ts
@@ -0,0 +1,54 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+'use strict';
+/**
+ * A type alias for a JSON primitive.
+ */
+export declare type JSONPrimitive = boolean | number | string | null;
+/**
+ * A type alias for a JSON value.
+ */
+export declare type JSONValue = JSONPrimitive | JSONObject | JSONArray;
+/**
+ * A type definition for a JSON object.
+ */
+export interface JSONObject {
+ [key: string]: JSONValue;
+}
+/**
+ * A type definition for a JSON array.
+ */
+export interface JSONArray extends Array {
+}
+/**
+ * A type definition for a readonly JSON object.
+ */
+export interface ReadonlyJSONObject {
+ readonly [key: string]: ReadonlyJSONValue;
+}
+/**
+ * A type definition for a readonly JSON array.
+ */
+export interface ReadonlyJSONArray extends ReadonlyArray {
+}
+/**
+ * A type alias for a readonly JSON value.
+ */
+export declare type ReadonlyJSONValue = JSONPrimitive | ReadonlyJSONObject | ReadonlyJSONArray;
+/**
+ * Test whether a JSON value is a primitive.
+ *
+ * @param value - The JSON value of interest.
+ *
+ * @returns `true` if the value is a primitive,`false` otherwise.
+ */
+export function isPrimitive(value: any): boolean {
+ return (
+ value === null ||
+ typeof value === 'boolean' ||
+ typeof value === 'number' ||
+ typeof value === 'string'
+ );
+}
diff --git a/src/sql/parts/notebook/outputs/common/mimemodel.ts b/src/sql/parts/notebook/outputs/common/mimemodel.ts
new file mode 100644
index 0000000000..3b88c489d7
--- /dev/null
+++ b/src/sql/parts/notebook/outputs/common/mimemodel.ts
@@ -0,0 +1,87 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+import { IRenderMime } from './renderMimeInterfaces';
+import { ReadonlyJSONObject } from './jsonext';
+
+/**
+ * The default mime model implementation.
+ */
+export class MimeModel implements IRenderMime.IMimeModel {
+ /**
+ * Construct a new mime model.
+ */
+ constructor(options: MimeModel.IOptions = {}) {
+ this.trusted = !!options.trusted;
+ this._data = options.data || {};
+ this._metadata = options.metadata || {};
+ this._callback = options.callback;
+ }
+
+ /**
+ * Whether the model is trusted.
+ */
+ readonly trusted: boolean;
+
+ /**
+ * The data associated with the model.
+ */
+ get data(): ReadonlyJSONObject {
+ return this._data;
+ }
+
+ /**
+ * The metadata associated with the model.
+ */
+ get metadata(): ReadonlyJSONObject {
+ return this._metadata;
+ }
+
+ /**
+ * Set the data associated with the model.
+ *
+ * #### Notes
+ * Depending on the implementation of the mime model,
+ * this call may or may not have deferred effects,
+ */
+ setData(options: IRenderMime.ISetDataOptions): void {
+ this._data = options.data || this._data;
+ this._metadata = options.metadata || this._metadata;
+ this._callback(options);
+ }
+
+ private _callback: (options: IRenderMime.ISetDataOptions) => void;
+ private _data: ReadonlyJSONObject;
+ private _metadata: ReadonlyJSONObject;
+}
+
+/**
+ * The namespace for MimeModel class statics.
+ */
+export namespace MimeModel {
+ /**
+ * The options used to create a mime model.
+ */
+ export interface IOptions {
+ /**
+ * Whether the model is trusted. Defaults to `false`.
+ */
+ trusted?: boolean;
+
+ /**
+ * A callback function for when the data changes.
+ */
+ callback?: (options: IRenderMime.ISetDataOptions) => void;
+
+ /**
+ * The initial mime data.
+ */
+ data?: ReadonlyJSONObject;
+
+ /**
+ * The initial mime metadata.
+ */
+ metadata?: ReadonlyJSONObject;
+ }
+}
\ No newline at end of file
diff --git a/src/sql/parts/notebook/outputs/common/nbformat.ts b/src/sql/parts/notebook/outputs/common/nbformat.ts
new file mode 100644
index 0000000000..12ebc816cb
--- /dev/null
+++ b/src/sql/parts/notebook/outputs/common/nbformat.ts
@@ -0,0 +1,494 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+// Notebook format interfaces
+// https://nbformat.readthedocs.io/en/latest/format_description.html
+// https://github.com/jupyter/nbformat/blob/master/nbformat/v4/nbformat.v4.schema.json
+
+
+import { JSONObject } from './jsonext';
+import { nb } from 'sqlops';
+
+/**
+ * A namespace for nbformat interfaces.
+ */
+export namespace nbformat {
+ /**
+ * The major version of the notebook format.
+ */
+ export const MAJOR_VERSION: number = 4;
+
+ /**
+ * The minor version of the notebook format.
+ */
+ export const MINOR_VERSION: number = 2;
+
+ /**
+ * The kernelspec metadata.
+ */
+ export interface IKernelspecMetadata extends JSONObject {
+ name: string;
+ display_name: string;
+ }
+
+ /**
+ * The language info metatda
+ */
+ export interface ILanguageInfoMetadata extends JSONObject {
+ name: string;
+ codemirror_mode?: string | JSONObject;
+ file_extension?: string;
+ mimetype?: string;
+ pygments_lexer?: string;
+ }
+
+ /**
+ * The default metadata for the notebook.
+ */
+ export interface INotebookMetadata extends JSONObject {
+ kernelspec?: IKernelspecMetadata;
+ language_info?: ILanguageInfoMetadata;
+ orig_nbformat: number;
+ }
+
+ /**
+ * The notebook content.
+ */
+ export interface INotebookContent {
+ metadata: INotebookMetadata;
+ nbformat_minor: number;
+ nbformat: number;
+ cells: ICell[];
+ }
+
+ /**
+ * A multiline string.
+ */
+ export type MultilineString = string | string[];
+
+ /**
+ * A mime-type keyed dictionary of data.
+ */
+ export interface IMimeBundle extends JSONObject {
+ [key: string]: MultilineString | JSONObject;
+ }
+
+ /**
+ * Media attachments (e.g. inline images).
+ */
+ export interface IAttachments {
+ [key: string]: IMimeBundle;
+ }
+
+ /**
+ * The code cell's prompt number. Will be null if the cell has not been run.
+ */
+ export type ExecutionCount = number | null;
+
+ /**
+ * Cell output metadata.
+ */
+ export type OutputMetadata = JSONObject;
+
+ /**
+ * Validate a mime type/value pair.
+ *
+ * @param type - The mimetype name.
+ *
+ * @param value - The value associated with the type.
+ *
+ * @returns Whether the type/value pair are valid.
+ */
+ export function validateMimeValue(
+ type: string,
+ value: MultilineString | JSONObject
+ ): boolean {
+ // Check if "application/json" or "application/foo+json"
+ const jsonTest = /^application\/(.*?)+\+json$/;
+ const isJSONType = type === 'application/json' || jsonTest.test(type);
+
+ let isString = (x: any) => {
+ return Object.prototype.toString.call(x) === '[object String]';
+ };
+
+ // If it is an array, make sure if is not a JSON type and it is an
+ // array of strings.
+ if (Array.isArray(value)) {
+ if (isJSONType) {
+ return false;
+ }
+ let valid = true;
+ (value as string[]).forEach(v => {
+ if (!isString(v)) {
+ valid = false;
+ }
+ });
+ return valid;
+ }
+
+ // If it is a string, make sure we are not a JSON type.
+ if (isString(value)) {
+ return !isJSONType;
+ }
+
+ // It is not a string, make sure it is a JSON type.
+ if (!isJSONType) {
+ return false;
+ }
+
+ // It is a JSON type, make sure it is a valid JSON object.
+ // return JSONExt.isObject(value);
+ return true;
+ }
+
+ /**
+ * Cell-level metadata.
+ */
+ export interface IBaseCellMetadata extends JSONObject {
+ /**
+ * Whether the cell is trusted.
+ *
+ * #### Notes
+ * This is not strictly part of the nbformat spec, but it is added by
+ * the contents manager.
+ *
+ * See https://jupyter-notebook.readthedocs.io/en/latest/security.html.
+ */
+ trusted: boolean;
+
+ /**
+ * The cell's name. If present, must be a non-empty string.
+ */
+ name: string;
+
+ /**
+ * The cell's tags. Tags must be unique, and must not contain commas.
+ */
+ tags: string[];
+ }
+
+ /**
+ * The base cell interface.
+ */
+ export interface IBaseCell {
+ /**
+ * String identifying the type of cell.
+ */
+ cell_type: string;
+
+ /**
+ * Contents of the cell, represented as an array of lines.
+ */
+ source: MultilineString;
+
+ /**
+ * Cell-level metadata.
+ */
+ metadata: Partial;
+ }
+
+ /**
+ * Metadata for the raw cell.
+ */
+ export interface IRawCellMetadata extends IBaseCellMetadata {
+ /**
+ * Raw cell metadata format for nbconvert.
+ */
+ format: string;
+ }
+
+ /**
+ * A raw cell.
+ */
+ export interface IRawCell extends IBaseCell {
+ /**
+ * String identifying the type of cell.
+ */
+ cell_type: 'raw';
+
+ /**
+ * Cell-level metadata.
+ */
+ metadata: Partial;
+
+ /**
+ * Cell attachments.
+ */
+ attachments?: IAttachments;
+ }
+
+ /**
+ * A markdown cell.
+ */
+ export interface IMarkdownCell extends IBaseCell {
+ /**
+ * String identifying the type of cell.
+ */
+ cell_type: 'markdown';
+
+ /**
+ * Cell attachments.
+ */
+ attachments?: IAttachments;
+ }
+
+ /**
+ * Metadata for a code cell.
+ */
+ export interface ICodeCellMetadata extends IBaseCellMetadata {
+ /**
+ * Whether the cell is collapsed/expanded.
+ */
+ collapsed: boolean;
+
+ /**
+ * Whether the cell's output is scrolled, unscrolled, or autoscrolled.
+ */
+ scrolled: boolean | 'auto';
+ }
+
+ /**
+ * A code cell.
+ */
+ export interface ICodeCell extends IBaseCell {
+ /**
+ * String identifying the type of cell.
+ */
+ cell_type: 'code';
+
+ /**
+ * Cell-level metadata.
+ */
+ metadata: Partial;
+
+ /**
+ * Execution, display, or stream outputs.
+ */
+ outputs: IOutput[];
+
+ /**
+ * The code cell's prompt number. Will be null if the cell has not been run.
+ */
+ execution_count: ExecutionCount;
+ }
+
+ /**
+ * An unrecognized cell.
+ */
+ export interface IUnrecognizedCell extends IBaseCell { }
+
+ /**
+ * A cell union type.
+ */
+ export type ICell = IRawCell | IMarkdownCell | ICodeCell | IUnrecognizedCell;
+
+ /**
+ * Test whether a cell is a raw cell.
+ */
+ export function isRaw(cell: ICell): cell is IRawCell {
+ return cell.cell_type === 'raw';
+ }
+
+ /**
+ * Test whether a cell is a markdown cell.
+ */
+ export function isMarkdown(cell: ICell): cell is IMarkdownCell {
+ return cell.cell_type === 'markdown';
+ }
+
+ /**
+ * Test whether a cell is a code cell.
+ */
+ export function isCode(cell: ICell): cell is ICodeCell {
+ return cell.cell_type === 'code';
+ }
+
+ /**
+ * A union metadata type.
+ */
+ export type ICellMetadata =
+ | IBaseCellMetadata
+ | IRawCellMetadata
+ | ICodeCellMetadata;
+
+ /**
+ * The valid output types.
+ */
+ export type OutputType =
+ | 'execute_result'
+ | 'display_data'
+ | 'stream'
+ | 'error'
+ | 'update_display_data';
+
+
+ /**
+ * Result of executing a code cell.
+ */
+ export interface IExecuteResult extends nb.ICellOutput {
+ /**
+ * Type of cell output.
+ */
+ output_type: 'execute_result';
+
+ /**
+ * A result's prompt number.
+ */
+ execution_count: ExecutionCount;
+
+ /**
+ * A mime-type keyed dictionary of data.
+ */
+ data: IMimeBundle;
+
+ /**
+ * Cell output metadata.
+ */
+ metadata: OutputMetadata;
+ }
+
+ /**
+ * Data displayed as a result of code cell execution.
+ */
+ export interface IDisplayData extends nb.ICellOutput {
+ /**
+ * Type of cell output.
+ */
+ output_type: 'display_data';
+
+ /**
+ * A mime-type keyed dictionary of data.
+ */
+ data: IMimeBundle;
+
+ /**
+ * Cell output metadata.
+ */
+ metadata: OutputMetadata;
+ }
+
+ /**
+ * Data displayed as an update to existing display data.
+ */
+ export interface IDisplayUpdate extends nb.ICellOutput {
+ /**
+ * Type of cell output.
+ */
+ output_type: 'update_display_data';
+
+ /**
+ * A mime-type keyed dictionary of data.
+ */
+ data: IMimeBundle;
+
+ /**
+ * Cell output metadata.
+ */
+ metadata: OutputMetadata;
+ }
+
+ /**
+ * Stream output from a code cell.
+ */
+ export interface IStream extends nb.ICellOutput {
+ /**
+ * Type of cell output.
+ */
+ output_type: 'stream';
+
+ /**
+ * The name of the stream.
+ */
+ name: StreamType;
+
+ /**
+ * The stream's text output.
+ */
+ text: MultilineString;
+ }
+
+ /**
+ * An alias for a stream type.
+ */
+ export type StreamType = 'stdout' | 'stderr';
+
+ /**
+ * Output of an error that occurred during code cell execution.
+ */
+ export interface IError extends nb.ICellOutput {
+ /**
+ * Type of cell output.
+ */
+ output_type: 'error';
+
+ /**
+ * The name of the error.
+ */
+ ename: string;
+
+ /**
+ * The value, or message, of the error.
+ */
+ evalue: string;
+
+ /**
+ * The error's traceback.
+ */
+ traceback: string[];
+ }
+
+ /**
+ * Unrecognized output.
+ */
+ export interface IUnrecognizedOutput extends nb.ICellOutput { }
+
+ /**
+ * Test whether an output is an execute result.
+ */
+ export function isExecuteResult(output: IOutput): output is IExecuteResult {
+ return output.output_type === 'execute_result';
+ }
+
+ /**
+ * Test whether an output is from display data.
+ */
+ export function isDisplayData(output: IOutput): output is IDisplayData {
+ return output.output_type === 'display_data';
+ }
+
+ /**
+ * Test whether an output is from updated display data.
+ */
+ export function isDisplayUpdate(output: IOutput): output is IDisplayUpdate {
+ return output.output_type === 'update_display_data';
+ }
+
+ /**
+ * Test whether an output is from a stream.
+ */
+ export function isStream(output: IOutput): output is IStream {
+ return output.output_type === 'stream';
+ }
+
+ /**
+ * Test whether an output is from a stream.
+ */
+ export function isError(output: IOutput): output is IError {
+ return output.output_type === 'error';
+ }
+
+ /**
+ * An output union type.
+ */
+ export type IOutput =
+ | IUnrecognizedOutput
+ | IExecuteResult
+ | IDisplayData
+ | IStream
+ | IError;
+}
+
+export interface ICellOutputWithIdAndTrust extends nb.ICellOutput {
+ id: number;
+ trusted: boolean;
+}
diff --git a/src/sql/parts/notebook/outputs/common/outputProcessor.ts b/src/sql/parts/notebook/outputs/common/outputProcessor.ts
new file mode 100644
index 0000000000..11ad262d25
--- /dev/null
+++ b/src/sql/parts/notebook/outputs/common/outputProcessor.ts
@@ -0,0 +1,110 @@
+
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+
+import { JSONObject } from './jsonext';
+import { MimeModel } from './mimemodel';
+import * as JSONExt from './jsonext';
+import { nbformat } from './nbformat';
+import { nb } from 'sqlops';
+
+/**
+ * A multiline string.
+ */
+export type MultilineString = string | string[];
+
+/**
+ * A mime-type keyed dictionary of data.
+ */
+export interface IMimeBundle extends JSONObject {
+ [key: string]: MultilineString | JSONObject;
+}
+
+/**
+ * Get the data from a notebook output.
+ */
+export function getData(output: nb.ICellOutput): JSONObject {
+ let bundle: IMimeBundle = {};
+ if (
+ nbformat.isExecuteResult(output) ||
+ nbformat.isDisplayData(output) ||
+ nbformat.isDisplayUpdate(output)
+ ) {
+ bundle = (output as nbformat.IExecuteResult).data;
+ } else if (nbformat.isStream(output)) {
+ if (output.name === 'stderr') {
+ bundle['application/vnd.jupyter.stderr'] = output.text;
+ } else {
+ bundle['application/vnd.jupyter.stdout'] = output.text;
+ }
+ } else if (nbformat.isError(output)) {
+ let traceback = output.traceback.join('\n');
+ bundle['application/vnd.jupyter.stderr'] =
+ traceback || `${output.ename}: ${output.evalue}`;
+ }
+ return convertBundle(bundle);
+}
+
+/**
+ * Get the metadata from an output message.
+ */
+export function getMetadata(output: nbformat.IOutput): JSONObject {
+ let value: JSONObject = Object.create(null);
+ if (nbformat.isExecuteResult(output) || nbformat.isDisplayData(output)) {
+ for (let key in output.metadata) {
+ value[key] = extract(output.metadata, key);
+ }
+ }
+ return value;
+}
+
+/**
+ * Get the bundle options given output model options.
+ */
+export function getBundleOptions(
+ options: IOutputModelOptions
+): MimeModel.IOptions {
+ let data = getData(options.value);
+ let metadata = getMetadata(options.value);
+ let trusted = !!options.trusted;
+ return { data, metadata, trusted };
+}
+
+/**
+ * Extract a value from a JSONObject.
+ */
+export function extract(value: JSONObject, key: string): {} {
+ let item = value[key];
+ if (JSONExt.isPrimitive(item)) {
+ return item;
+ }
+ return JSON.parse(JSON.stringify(item));
+}
+
+/**
+ * Convert a mime bundle to mime data.
+ */
+function convertBundle(bundle: nbformat.IMimeBundle): JSONObject {
+ let map: JSONObject = Object.create(null);
+ for (let mimeType in bundle) {
+ map[mimeType] = extract(bundle, mimeType);
+ }
+ return map;
+}
+
+/**
+ * The options used to create a notebook output model.
+ */
+export interface IOutputModelOptions {
+ /**
+ * The raw output value.
+ */
+ value: nbformat.IOutput;
+
+ /**
+ * Whether the output is trusted. The default is false.
+ */
+ trusted?: boolean;
+}
\ No newline at end of file
diff --git a/src/sql/parts/notebook/outputs/common/renderMimeInterfaces.ts b/src/sql/parts/notebook/outputs/common/renderMimeInterfaces.ts
new file mode 100644
index 0000000000..3585a0d112
--- /dev/null
+++ b/src/sql/parts/notebook/outputs/common/renderMimeInterfaces.ts
@@ -0,0 +1,360 @@
+
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+import { ReadonlyJSONObject } from './jsonext';
+
+/**
+ * A namespace for rendermime associated interfaces.
+ */
+export namespace IRenderMime {
+ /**
+ * A model for mime data.
+ */
+ export interface IMimeModel {
+ /**
+ * Whether the data in the model is trusted.
+ */
+ readonly trusted: boolean;
+
+ /**
+ * The data associated with the model.
+ */
+ readonly data: ReadonlyJSONObject;
+
+ /**
+ * The metadata associated with the model.
+ */
+ readonly metadata: ReadonlyJSONObject;
+
+ /**
+ * Set the data associated with the model.
+ *
+ * #### Notes
+ * Calling this function may trigger an asynchronous operation
+ * that could cause the renderer to be rendered with a new model
+ * containing the new data.
+ */
+ setData(options: ISetDataOptions): void;
+ }
+
+ /**
+ * The options used to update a mime model.
+ */
+ export interface ISetDataOptions {
+ /**
+ * The new data object.
+ */
+ data?: ReadonlyJSONObject;
+
+ /**
+ * The new metadata object.
+ */
+ metadata?: ReadonlyJSONObject;
+ }
+
+
+ /**
+ * The options used to initialize a document widget factory.
+ *
+ * This interface is intended to be used by mime renderer extensions
+ * to define a document opener that uses its renderer factory.
+ */
+ export interface IDocumentWidgetFactoryOptions {
+ /**
+ * The name of the widget to display in dialogs.
+ */
+ readonly name: string;
+
+ /**
+ * The name of the document model type.
+ */
+ readonly modelName?: string;
+
+ /**
+ * The primary file type of the widget.
+ */
+ readonly primaryFileType: string;
+
+ /**
+ * The file types the widget can view.
+ */
+ readonly fileTypes: ReadonlyArray;
+
+ /**
+ * The file types for which the factory should be the default.
+ */
+ readonly defaultFor?: ReadonlyArray;
+
+ /**
+ * The file types for which the factory should be the default for rendering,
+ * if that is different than the default factory (which may be for editing)
+ * If undefined, then it will fall back on the default file type.
+ */
+ readonly defaultRendered?: ReadonlyArray;
+ }
+
+ /**
+ * A file type to associate with the renderer.
+ */
+ export interface IFileType {
+ /**
+ * The name of the file type.
+ */
+ readonly name: string;
+
+ /**
+ * The mime types associated the file type.
+ */
+ readonly mimeTypes: ReadonlyArray;
+
+ /**
+ * The extensions of the file type (e.g. `".txt"`). Can be a compound
+ * extension (e.g. `".table.json`).
+ */
+ readonly extensions: ReadonlyArray;
+
+ /**
+ * An optional display name for the file type.
+ */
+ readonly displayName?: string;
+
+ /**
+ * An optional pattern for a file name (e.g. `^Dockerfile$`).
+ */
+ readonly pattern?: string;
+
+ /**
+ * The icon class name for the file type.
+ */
+ readonly iconClass?: string;
+
+ /**
+ * The icon label for the file type.
+ */
+ readonly iconLabel?: string;
+
+ /**
+ * The file format for the file type ('text', 'base64', or 'json').
+ */
+ readonly fileFormat?: string;
+ }
+
+ /**
+ * An interface for using a RenderMime.IRenderer for output and read-only documents.
+ */
+ export interface IExtension {
+ /**
+ * The ID of the extension.
+ *
+ * #### Notes
+ * The convention for extension IDs in JupyterLab is the full NPM package
+ * name followed by a colon and a unique string token, e.g.
+ * `'@jupyterlab/apputils-extension:settings'` or `'foo-extension:bar'`.
+ */
+ readonly id: string;
+
+ /**
+ * A renderer factory to be registered to render the MIME type.
+ */
+ readonly rendererFactory: IRendererFactory;
+
+ /**
+ * The rank passed to `RenderMime.addFactory`. If not given,
+ * defaults to the `defaultRank` of the factory.
+ */
+ readonly rank?: number;
+
+ /**
+ * The timeout after user activity to re-render the data.
+ */
+ readonly renderTimeout?: number;
+
+ /**
+ * Preferred data type from the model. Defaults to `string`.
+ */
+ readonly dataType?: 'string' | 'json';
+
+ /**
+ * The options used to open a document with the renderer factory.
+ */
+ readonly documentWidgetFactoryOptions?:
+ | IDocumentWidgetFactoryOptions
+ | ReadonlyArray;
+
+ /**
+ * The optional file type associated with the extension.
+ */
+ readonly fileTypes?: ReadonlyArray;
+ }
+
+ /**
+ * The interface for a module that exports an extension or extensions as
+ * the default value.
+ */
+ export interface IExtensionModule {
+ /**
+ * The default export.
+ */
+ readonly default: IExtension | ReadonlyArray;
+ }
+
+ /**
+ * A widget which displays the contents of a mime model.
+ */
+ export interface IRenderer {
+ /**
+ * Render a mime model.
+ *
+ * @param model - The mime model to render.
+ *
+ * @returns A promise which resolves when rendering is complete.
+ *
+ * #### Notes
+ * This method may be called multiple times during the lifetime
+ * of the widget to update it if and when new data is available.
+ */
+ renderModel(model: IRenderMime.IMimeModel): Promise;
+
+ /**
+ * Node to be updated by the renderer
+ */
+ node: HTMLElement;
+ }
+
+ /**
+ * The interface for a renderer factory.
+ */
+ export interface IRendererFactory {
+ /**
+ * Whether the factory is a "safe" factory.
+ *
+ * #### Notes
+ * A "safe" factory produces renderer widgets which can render
+ * untrusted model data in a usable way. *All* renderers must
+ * handle untrusted data safely, but some may simply failover
+ * with a "Run cell to view output" message. A "safe" renderer
+ * is an indication that its sanitized output will be useful.
+ */
+ readonly safe: boolean;
+
+ /**
+ * The mime types handled by this factory.
+ */
+ readonly mimeTypes: ReadonlyArray;
+
+ /**
+ * The default rank of the factory. If not given, defaults to 100.
+ */
+ readonly defaultRank?: number;
+
+ /**
+ * Create a renderer which displays the mime data.
+ *
+ * @param options - The options used to render the data.
+ */
+ createRenderer(options: IRendererOptions): IRenderer;
+ }
+
+ /**
+ * The options used to create a renderer.
+ */
+ export interface IRendererOptions {
+ /**
+ * The preferred mimeType to render.
+ */
+ mimeType: string;
+
+ /**
+ * The html sanitizer.
+ */
+ sanitizer: ISanitizer;
+
+ /**
+ * An optional url resolver.
+ */
+ resolver: IResolver | null;
+
+ /**
+ * An optional link handler.
+ */
+ linkHandler: ILinkHandler | null;
+
+ /**
+ * The LaTeX typesetter.
+ */
+ latexTypesetter: ILatexTypesetter | null;
+ }
+
+ /**
+ * An object that handles html sanitization.
+ */
+ export interface ISanitizer {
+ /**
+ * Sanitize an HTML string.
+ */
+ sanitize(dirty: string): string;
+ }
+
+ /**
+ * An object that handles links on a node.
+ */
+ export interface ILinkHandler {
+ /**
+ * Add the link handler to the node.
+ *
+ * @param node: the node for which to handle the link.
+ *
+ * @param path: the path to open when the link is clicked.
+ *
+ * @param id: an optional element id to scroll to when the path is opened.
+ */
+ handleLink(node: HTMLElement, path: string, id?: string): void;
+ }
+
+ /**
+ * An object that resolves relative URLs.
+ */
+ export interface IResolver {
+ /**
+ * Resolve a relative url to a correct server path.
+ */
+ resolveUrl(url: string): Promise;
+
+ /**
+ * Get the download url of a given absolute server path.
+ */
+ getDownloadUrl(path: string): Promise;
+
+ /**
+ * Whether the URL should be handled by the resolver
+ * or not.
+ *
+ * #### Notes
+ * This is similar to the `isLocal` check in `URLExt`,
+ * but can also perform additional checks on whether the
+ * resolver should handle a given URL.
+ */
+ isLocal?: (url: string) => boolean;
+ }
+
+ /**
+ * The interface for a LaTeX typesetter.
+ */
+ export interface ILatexTypesetter {
+ /**
+ * Typeset a DOM element.
+ *
+ * @param element - the DOM element to typeset. The typesetting may
+ * happen synchronously or asynchronously.
+ *
+ * #### Notes
+ * The application-wide rendermime object has a settable
+ * `latexTypesetter` property which is used wherever LaTeX
+ * typesetting is required. Extensions wishing to provide their
+ * own typesetter may replace that on the global `lab.rendermime`.
+ */
+ typeset(element: HTMLElement): void;
+ }
+}
diff --git a/src/sql/parts/notebook/outputs/common/url.ts b/src/sql/parts/notebook/outputs/common/url.ts
new file mode 100644
index 0000000000..5386ee1daa
--- /dev/null
+++ b/src/sql/parts/notebook/outputs/common/url.ts
@@ -0,0 +1,184 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import { JSONObject } from './jsonext';
+import URI from 'vs/base/common/uri';
+
+/**
+ * The namespace for URL-related functions.
+ */
+export namespace URLExt {
+ /**
+ * Normalize a url.
+ */
+ export function normalize(url: string): string {
+ return URI.parse(url).toString();
+ }
+
+ /**
+ * Join a sequence of url components and normalizes as in node `path.join`.
+ *
+ * @param parts - The url components.
+ *
+ * @returns the joined url.
+ */
+ export function join(...parts: string[]): string {
+ parts = parts || [];
+
+ // Isolate the top element.
+ const top = parts[0] || '';
+
+ // Check whether protocol shorthand is being used.
+ const shorthand = top.indexOf('//') === 0;
+
+ // Parse the top element into a header collection.
+ const header = top.match(/(\w+)(:)(\/\/)?/);
+ const protocol = header && header[1];
+ const colon = protocol && header[2];
+ const slashes = colon && header[3];
+
+ // Construct the URL prefix.
+ const prefix = shorthand
+ ? '//'
+ : [protocol, colon, slashes].filter(str => str).join('');
+
+ // Construct the URL body omitting the prefix of the top value.
+ const body = [top.indexOf(prefix) === 0 ? top.replace(prefix, '') : top]
+ // Filter out top value if empty.
+ .filter(str => str)
+ // Remove leading slashes in all subsequent URL body elements.
+ .concat(parts.slice(1).map(str => str.replace(/^\//, '')))
+ .join('/')
+ // Replace multiple slashes with one.
+ .replace(/\/+/g, '/');
+
+ return prefix + body;
+ }
+
+ /**
+ * Encode the components of a multi-segment url.
+ *
+ * @param url - The url to encode.
+ *
+ * @returns the encoded url.
+ *
+ * #### Notes
+ * Preserves the `'/'` separators.
+ * Should not include the base url, since all parts are escaped.
+ */
+ export function encodeParts(url: string): string {
+ return join(...url.split('/').map(encodeURIComponent));
+ }
+
+ /**
+ * Return a serialized object string suitable for a query.
+ *
+ * @param object - The source object.
+ *
+ * @returns an encoded url query.
+ *
+ * #### Notes
+ * Modified version of [stackoverflow](http://stackoverflow.com/a/30707423).
+ */
+ export function objectToQueryString(value: JSONObject): string {
+ const keys = Object.keys(value);
+
+ if (!keys.length) {
+ return '';
+ }
+
+ return (
+ '?' +
+ keys
+ .map(key => {
+ const content = encodeURIComponent(String(value[key]));
+
+ return key + (content ? '=' + content : '');
+ })
+ .join('&')
+ );
+ }
+
+ /**
+ * Return a parsed object that represents the values in a query string.
+ */
+ export function queryStringToObject(
+ value: string
+ ): { [key: string]: string } {
+ return value
+ .replace(/^\?/, '')
+ .split('&')
+ .reduce(
+ (acc, val) => {
+ const [key, value] = val.split('=');
+
+ acc[key] = decodeURIComponent(value || '');
+
+ return acc;
+ },
+ {} as { [key: string]: string }
+ );
+ }
+
+ /**
+ * Test whether the url is a local url.
+ *
+ * #### Notes
+ * This function returns `false` for any fully qualified url, including
+ * `data:`, `file:`, and `//` protocol URLs.
+ */
+ export function isLocal(url: string): boolean {
+ // If if doesn't have a scheme such as file: or http:// it's local
+ return !!URI.parse(url).scheme;
+ }
+
+ /**
+ * The interface for a URL object
+ */
+ export interface IUrl {
+ /**
+ * The full URL string that was parsed with both the protocol and host
+ * components converted to lower-case.
+ */
+ href?: string;
+
+ /**
+ * Identifies the URL's lower-cased protocol scheme.
+ */
+ protocol?: string;
+
+ /**
+ * The full lower-cased host portion of the URL, including the port if
+ * specified.
+ */
+ host?: string;
+
+ /**
+ * The lower-cased host name portion of the host component without the
+ * port included.
+ */
+ hostname?: string;
+
+ /**
+ * The numeric port portion of the host component.
+ */
+ port?: string;
+
+ /**
+ * The entire path section of the URL.
+ */
+ pathname?: string;
+
+ /**
+ * The "fragment" portion of the URL including the leading ASCII hash
+ * `(#)` character
+ */
+ hash?: string;
+
+ /**
+ * The search element, including leading question mark (`'?'`), if any,
+ * of the URL.
+ */
+ search?: string;
+ }
+}
diff --git a/src/sql/parts/notebook/outputs/factories.ts b/src/sql/parts/notebook/outputs/factories.ts
new file mode 100644
index 0000000000..a34d1cffa1
--- /dev/null
+++ b/src/sql/parts/notebook/outputs/factories.ts
@@ -0,0 +1,94 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+
+import * as widgets from './widgets';
+import { IRenderMime } from './common/renderMimeInterfaces';
+
+/**
+ * A mime renderer factory for raw html.
+ */
+export const htmlRendererFactory: IRenderMime.IRendererFactory = {
+ safe: true,
+ mimeTypes: ['text/html'],
+ defaultRank: 50,
+ createRenderer: options => new widgets.RenderedHTML(options)
+};
+
+/**
+ * A mime renderer factory for images.
+ */
+export const imageRendererFactory: IRenderMime.IRendererFactory = {
+ safe: true,
+ mimeTypes: ['image/bmp', 'image/png', 'image/jpeg', 'image/gif'],
+ defaultRank: 90,
+ createRenderer: options => new widgets.RenderedImage(options)
+};
+
+// /**
+// * A mime renderer factory for LaTeX.
+// */
+// export const latexRendererFactory: IRenderMime.IRendererFactory = {
+// safe: true,
+// mimeTypes: ['text/latex'],
+// defaultRank: 70,
+// createRenderer: options => new widgets.RenderedLatex(options)
+// };
+
+// /**
+// * A mime renderer factory for Markdown.
+// */
+// export const markdownRendererFactory: IRenderMime.IRendererFactory = {
+// safe: true,
+// mimeTypes: ['text/markdown'],
+// defaultRank: 60,
+// createRenderer: options => new widgets.RenderedMarkdown(options)
+// };
+
+/**
+ * A mime renderer factory for svg.
+ */
+export const svgRendererFactory: IRenderMime.IRendererFactory = {
+ safe: false,
+ mimeTypes: ['image/svg+xml'],
+ defaultRank: 80,
+ createRenderer: options => new widgets.RenderedSVG(options)
+};
+
+/**
+ * A mime renderer factory for plain and jupyter console text data.
+ */
+export const textRendererFactory: IRenderMime.IRendererFactory = {
+ safe: true,
+ mimeTypes: [
+ 'text/plain',
+ 'application/vnd.jupyter.stdout',
+ 'application/vnd.jupyter.stderr'
+ ],
+ defaultRank: 120,
+ createRenderer: options => new widgets.RenderedText(options)
+};
+
+/**
+ * A placeholder factory for deprecated rendered JavaScript.
+ */
+export const javaScriptRendererFactory: IRenderMime.IRendererFactory = {
+ safe: false,
+ mimeTypes: ['text/javascript', 'application/javascript'],
+ defaultRank: 110,
+ createRenderer: options => new widgets.RenderedJavaScript(options)
+};
+
+/**
+ * The standard factories provided by the rendermime package.
+ */
+export const standardRendererFactories: ReadonlyArray = [
+ htmlRendererFactory,
+ // markdownRendererFactory,
+ // latexRendererFactory,
+ svgRendererFactory,
+ imageRendererFactory,
+ javaScriptRendererFactory,
+ textRendererFactory
+];
diff --git a/src/sql/parts/notebook/outputs/registry.ts b/src/sql/parts/notebook/outputs/registry.ts
new file mode 100644
index 0000000000..b35004e696
--- /dev/null
+++ b/src/sql/parts/notebook/outputs/registry.ts
@@ -0,0 +1,352 @@
+
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+import { IRenderMime } from './common/renderMimeInterfaces';
+import { MimeModel } from './common/mimemodel';
+import { ReadonlyJSONObject } from './common/jsonext';
+import { defaultSanitizer } from './sanitizer';
+
+/**
+ * An object which manages mime renderer factories.
+ *
+ * This object is used to render mime models using registered mime
+ * renderers, selecting the preferred mime renderer to render the
+ * model into a widget.
+ *
+ * #### Notes
+ * This class is not intended to be subclassed.
+ */
+export class RenderMimeRegistry {
+ /**
+ * Construct a new rendermime.
+ *
+ * @param options - The options for initializing the instance.
+ */
+ constructor(options: RenderMimeRegistry.IOptions = {}) {
+ // Parse the options.
+ this.resolver = options.resolver || null;
+ this.linkHandler = options.linkHandler || null;
+ this.latexTypesetter = options.latexTypesetter || null;
+ this.sanitizer = options.sanitizer || defaultSanitizer;
+
+ // Add the initial factories.
+ if (options.initialFactories) {
+ for (let factory of options.initialFactories) {
+ this.addFactory(factory);
+ }
+ }
+ }
+
+ /**
+ * The sanitizer used by the rendermime instance.
+ */
+ readonly sanitizer: IRenderMime.ISanitizer;
+
+ /**
+ * The object used to resolve relative urls for the rendermime instance.
+ */
+ readonly resolver: IRenderMime.IResolver | null;
+
+ /**
+ * The object used to handle path opening links.
+ */
+ readonly linkHandler: IRenderMime.ILinkHandler | null;
+
+ /**
+ * The LaTeX typesetter for the rendermime.
+ */
+ readonly latexTypesetter: IRenderMime.ILatexTypesetter | null;
+
+ /**
+ * The ordered list of mimeTypes.
+ */
+ get mimeTypes(): ReadonlyArray {
+ return this._types || (this._types = Private.sortedTypes(this._ranks));
+ }
+
+ /**
+ * Find the preferred mime type for a mime bundle.
+ *
+ * @param bundle - The bundle of mime data.
+ *
+ * @param safe - How to consider safe/unsafe factories. If 'ensure',
+ * it will only consider safe factories. If 'any', any factory will be
+ * considered. If 'prefer', unsafe factories will be considered, but
+ * only after the safe options have been exhausted.
+ *
+ * @returns The preferred mime type from the available factories,
+ * or `undefined` if the mime type cannot be rendered.
+ */
+ preferredMimeType(
+ bundle: ReadonlyJSONObject,
+ safe: 'ensure' | 'prefer' | 'any' = 'ensure'
+ ): string | undefined {
+ // Try to find a safe factory first, if preferred.
+ if (safe === 'ensure' || safe === 'prefer') {
+ for (let mt of this.mimeTypes) {
+ if (mt in bundle && this._factories[mt].safe) {
+ return mt;
+ }
+ }
+ }
+
+ if (safe !== 'ensure') {
+ // Otherwise, search for the best factory among all factories.
+ for (let mt of this.mimeTypes) {
+ if (mt in bundle) {
+ return mt;
+ }
+ }
+ }
+
+ // Otherwise, no matching mime type exists.
+ return undefined;
+ }
+
+ /**
+ * Create a renderer for a mime type.
+ *
+ * @param mimeType - The mime type of interest.
+ *
+ * @returns A new renderer for the given mime type.
+ *
+ * @throws An error if no factory exists for the mime type.
+ */
+ createRenderer(mimeType: string): IRenderMime.IRenderer {
+ // Throw an error if no factory exists for the mime type.
+ if (!(mimeType in this._factories)) {
+ throw new Error(`No factory for mime type: '${mimeType}'`);
+ }
+
+ // Invoke the best factory for the given mime type.
+ return this._factories[mimeType].createRenderer({
+ mimeType,
+ resolver: this.resolver,
+ sanitizer: this.sanitizer,
+ linkHandler: this.linkHandler,
+ latexTypesetter: this.latexTypesetter
+ });
+ }
+
+ /**
+ * Create a new mime model. This is a convenience method.
+ *
+ * @options - The options used to create the model.
+ *
+ * @returns A new mime model.
+ */
+ createModel(options: MimeModel.IOptions = {}): MimeModel {
+ return new MimeModel(options);
+ }
+
+ /**
+ * Create a clone of this rendermime instance.
+ *
+ * @param options - The options for configuring the clone.
+ *
+ * @returns A new independent clone of the rendermime.
+ */
+ clone(options: RenderMimeRegistry.ICloneOptions = {}): RenderMimeRegistry {
+ // Create the clone.
+ let clone = new RenderMimeRegistry({
+ resolver: options.resolver || this.resolver || undefined,
+ sanitizer: options.sanitizer || this.sanitizer || undefined,
+ linkHandler: options.linkHandler || this.linkHandler || undefined,
+ latexTypesetter: options.latexTypesetter || this.latexTypesetter
+ });
+
+ // Clone the internal state.
+ clone._factories = { ...this._factories };
+ clone._ranks = { ...this._ranks };
+ clone._id = this._id;
+
+ // Return the cloned object.
+ return clone;
+ }
+
+ /**
+ * Get the renderer factory registered for a mime type.
+ *
+ * @param mimeType - The mime type of interest.
+ *
+ * @returns The factory for the mime type, or `undefined`.
+ */
+ getFactory(mimeType: string): IRenderMime.IRendererFactory | undefined {
+ return this._factories[mimeType];
+ }
+
+ /**
+ * Add a renderer factory to the rendermime.
+ *
+ * @param factory - The renderer factory of interest.
+ *
+ * @param rank - The rank of the renderer. A lower rank indicates
+ * a higher priority for rendering. If not given, the rank will
+ * defer to the `defaultRank` of the factory. If no `defaultRank`
+ * is given, it will default to 100.
+ *
+ * #### Notes
+ * The renderer will replace an existing renderer for the given
+ * mimeType.
+ */
+ addFactory(factory: IRenderMime.IRendererFactory, rank?: number): void {
+ if (rank === undefined) {
+ rank = factory.defaultRank;
+ if (rank === undefined) {
+ rank = 100;
+ }
+ }
+ for (let mt of factory.mimeTypes) {
+ this._factories[mt] = factory;
+ this._ranks[mt] = { rank, id: this._id++ };
+ }
+ this._types = null;
+ }
+
+ /**
+ * Remove a mime type.
+ *
+ * @param mimeType - The mime type of interest.
+ */
+ removeMimeType(mimeType: string): void {
+ delete this._factories[mimeType];
+ delete this._ranks[mimeType];
+ this._types = null;
+ }
+
+ /**
+ * Get the rank for a given mime type.
+ *
+ * @param mimeType - The mime type of interest.
+ *
+ * @returns The rank of the mime type or undefined.
+ */
+ getRank(mimeType: string): number | undefined {
+ let rank = this._ranks[mimeType];
+ return rank && rank.rank;
+ }
+
+ /**
+ * Set the rank of a given mime type.
+ *
+ * @param mimeType - The mime type of interest.
+ *
+ * @param rank - The new rank to assign.
+ *
+ * #### Notes
+ * This is a no-op if the mime type is not registered.
+ */
+ setRank(mimeType: string, rank: number): void {
+ if (!this._ranks[mimeType]) {
+ return;
+ }
+ let id = this._id++;
+ this._ranks[mimeType] = { rank, id };
+ this._types = null;
+ }
+
+ private _id = 0;
+ private _ranks: Private.RankMap = {};
+ private _types: string[] | null = null;
+ private _factories: Private.FactoryMap = {};
+}
+
+/**
+ * The namespace for `RenderMimeRegistry` class statics.
+ */
+export namespace RenderMimeRegistry {
+ /**
+ * The options used to initialize a rendermime instance.
+ */
+ export interface IOptions {
+ /**
+ * Initial factories to add to the rendermime instance.
+ */
+ initialFactories?: ReadonlyArray;
+
+ /**
+ * The sanitizer used to sanitize untrusted html inputs.
+ *
+ * If not given, a default sanitizer will be used.
+ */
+ sanitizer?: IRenderMime.ISanitizer;
+
+ /**
+ * The initial resolver object.
+ *
+ * The default is `null`.
+ */
+ resolver?: IRenderMime.IResolver;
+
+ /**
+ * An optional path handler.
+ */
+ linkHandler?: IRenderMime.ILinkHandler;
+
+ /**
+ * An optional LaTeX typesetter.
+ */
+ latexTypesetter?: IRenderMime.ILatexTypesetter;
+ }
+
+ /**
+ * The options used to clone a rendermime instance.
+ */
+ export interface ICloneOptions {
+ /**
+ * The new sanitizer used to sanitize untrusted html inputs.
+ */
+ sanitizer?: IRenderMime.ISanitizer;
+
+ /**
+ * The new resolver object.
+ */
+ resolver?: IRenderMime.IResolver;
+
+ /**
+ * The new path handler.
+ */
+ linkHandler?: IRenderMime.ILinkHandler;
+
+ /**
+ * The new LaTeX typesetter.
+ */
+ latexTypesetter?: IRenderMime.ILatexTypesetter;
+ }
+}
+
+/**
+ * The namespace for the module implementation details.
+ */
+namespace Private {
+ /**
+ * A type alias for a mime rank and tie-breaking id.
+ */
+ export type RankPair = { readonly id: number; readonly rank: number };
+
+ /**
+ * A type alias for a mapping of mime type -> rank pair.
+ */
+ export type RankMap = { [key: string]: RankPair };
+
+ /**
+ * A type alias for a mapping of mime type -> ordered factories.
+ */
+ export type FactoryMap = { [key: string]: IRenderMime.IRendererFactory };
+
+ /**
+ * Get the mime types in the map, ordered by rank.
+ */
+ export function sortedTypes(map: RankMap): string[] {
+ return Object.keys(map).sort((a, b) => {
+ let p1 = map[a];
+ let p2 = map[b];
+ if (p1.rank !== p2.rank) {
+ return p1.rank - p2.rank;
+ }
+ return p1.id - p2.id;
+ });
+ }
+}
diff --git a/src/sql/parts/notebook/outputs/renderers.ts b/src/sql/parts/notebook/outputs/renderers.ts
new file mode 100644
index 0000000000..498ebe0435
--- /dev/null
+++ b/src/sql/parts/notebook/outputs/renderers.ts
@@ -0,0 +1,629 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+
+import { default as AnsiUp } from 'ansi_up';
+import { IRenderMime } from './common/renderMimeInterfaces';
+import { URLExt } from './common/url';
+import URI from 'vs/base/common/uri';
+
+
+/**
+ * Render HTML into a host node.
+ *
+ * @params options - The options for rendering.
+ *
+ * @returns A promise which resolves when rendering is complete.
+ */
+export function renderHTML(options: renderHTML.IOptions): Promise {
+ // Unpack the options.
+ let {
+ host,
+ source,
+ trusted,
+ sanitizer,
+ resolver,
+ linkHandler,
+ shouldTypeset,
+ latexTypesetter
+ } = options;
+
+ let originalSource = source;
+
+ // Bail early if the source is empty.
+ if (!source) {
+ host.textContent = '';
+ return Promise.resolve(undefined);
+ }
+
+ // Sanitize the source if it is not trusted. This removes all
+ // `