diff --git a/bower.json b/bower.json index c1ee47b7539..0b12ebee282 100644 --- a/bower.json +++ b/bower.json @@ -3,7 +3,7 @@ "dependencies": { "html5shiv": "3.6.2", "jquery": "2.2.0", - "prism": "1.15.0", + "prism": "1.16.0", "selectivizr": "https://github.com/keithclark/selectivizr.git#1.0.2" }, "install": { @@ -20,6 +20,7 @@ "bower_components/prism/components/prism-clike.js", "bower_components/prism/components/prism-javascript.js", "bower_components/prism/components/prism-json.js", + "bower_components/prism/components/prism-jsonp.js", "bower_components/prism/components/prism-css-extras.js", "bower_components/prism/components/prism-rust.js", "bower_components/prism/plugins/line-highlight/prism-line-highlight.js", diff --git a/kuma/settings/common.py b/kuma/settings/common.py index c1fa07b98c8..71249974c49 100644 --- a/kuma/settings/common.py +++ b/kuma/settings/common.py @@ -1051,6 +1051,7 @@ def pipeline_one_scss(slug, **kwargs): "js/libs/prism/prism-clike.js", "js/libs/prism/prism-javascript.js", "js/libs/prism/prism-json.js", + "js/libs/prism/prism-jsonp.js", "js/libs/prism/prism-css-extras.js", "js/libs/prism/prism-rust.js", "js/libs/prism/prism-line-highlight.js", diff --git a/kuma/static/js/libs/prism/prism-clike.js b/kuma/static/js/libs/prism/prism-clike.js index f72eba6002c..e0257162db9 100644 --- a/kuma/static/js/libs/prism/prism-clike.js +++ b/kuma/static/js/libs/prism/prism-clike.js @@ -23,7 +23,7 @@ Prism.languages.clike = { }, 'keyword': /\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/, 'boolean': /\b(?:true|false)\b/, - 'function': /[a-z0-9_]+(?=\()/i, + 'function': /\w+(?=\()/, 'number': /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i, 'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/, 'punctuation': /[{}[\];(),.:]/ diff --git a/kuma/static/js/libs/prism/prism-core.js b/kuma/static/js/libs/prism/prism-core.js index 29330e55330..799a3e5a965 100644 --- a/kuma/static/js/libs/prism/prism-core.js +++ b/kuma/static/js/libs/prism/prism-core.js @@ -12,20 +12,20 @@ var _self = (typeof window !== 'undefined') * @author Lea Verou http://lea.verou.me */ -var Prism = (function(){ +var Prism = (function (_self){ // Private helper vars var lang = /\blang(?:uage)?-([\w-]+)\b/i; var uniqueId = 0; -var _ = _self.Prism = { +var _ = { manual: _self.Prism && _self.Prism.manual, disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler, util: { encode: function (tokens) { if (tokens instanceof Token) { return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias); - } else if (_.util.type(tokens) === 'Array') { + } else if (Array.isArray(tokens)) { return tokens.map(_.util.encode); } else { return tokens.replace(/&/g, '&').replace(/)[\s\S]*?(?=<\/style>)/i, - lookbehind: true, - inside: Prism.languages.css, - alias: 'language-css', + Prism.languages.css = { + 'comment': /\/\*[\s\S]*?\*\//, + 'atrule': { + pattern: /@[\w-]+?[\s\S]*?(?:;|(?=\s*\{))/i, + inside: { + 'rule': /@[\w-]+/ + // See rest below + } + }, + 'url': RegExp('url\\((?:' + string.source + '|.*?)\\)', 'i'), + 'selector': RegExp('[^{}\\s](?:[^{};"\']|' + string.source + ')*?(?=\\s*\\{)'), + 'string': { + pattern: string, greedy: true - } - }); + }, + 'property': /[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i, + 'important': /!important\b/i, + 'function': /[-a-z0-9]+(?=\()/i, + 'punctuation': /[(){};:,]/ + }; - Prism.languages.insertBefore('inside', 'attr-value', { - 'style-attr': { - pattern: /\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i, - inside: { - 'attr-name': { - pattern: /^\s*style/i, - inside: Prism.languages.markup.tag.inside + Prism.languages.css['atrule'].inside.rest = Prism.languages.css; + + var markup = Prism.languages.markup; + if (markup) { + markup.tag.addInlined('style', 'css'); + + Prism.languages.insertBefore('inside', 'attr-value', { + 'style-attr': { + pattern: /\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i, + inside: { + 'attr-name': { + pattern: /^\s*style/i, + inside: markup.tag.inside + }, + 'punctuation': /^\s*=\s*['"]|['"]\s*$/, + 'attr-value': { + pattern: /.+/i, + inside: Prism.languages.css + } }, - 'punctuation': /^\s*=\s*['"]|['"]\s*$/, - 'attr-value': { - pattern: /.+/i, - inside: Prism.languages.css - } - }, - alias: 'language-css' - } - }, Prism.languages.markup.tag); -} \ No newline at end of file + alias: 'language-css' + } + }, markup.tag); + } + +}(Prism)); diff --git a/kuma/static/js/libs/prism/prism-javascript.js b/kuma/static/js/libs/prism/prism-javascript.js index 7800a7d424c..b27874b0258 100644 --- a/kuma/static/js/libs/prism/prism-javascript.js +++ b/kuma/static/js/libs/prism/prism-javascript.js @@ -1,23 +1,62 @@ Prism.languages.javascript = Prism.languages.extend('clike', { - 'keyword': /\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/, - 'number': /\b(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/, + 'class-name': [ + Prism.languages.clike['class-name'], + { + pattern: /(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/, + lookbehind: true + } + ], + 'keyword': [ + { + pattern: /((?:^|})\s*)(?:catch|finally)\b/, + lookbehind: true + }, + { + pattern: /(^|[^.])\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/, + lookbehind: true + }, + ], + 'number': /\b(?:(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+)n?|\d+n|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/, // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444) - 'function': /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/i, + 'function': /[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, 'operator': /-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/ }); +Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/ + Prism.languages.insertBefore('javascript', 'keyword', { 'regex': { - pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[[^\]\r\n]+]|\\.|[^/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})\]]))/, + pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})\]]))/, lookbehind: true, greedy: true }, // This must be declared before keyword because we use "function" inside the look-forward 'function-variable': { - pattern: /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=\s*(?:function\b|(?:\([^()]*\)|[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/i, + pattern: /[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/, alias: 'function' }, - 'constant': /\b[A-Z][A-Z\d_]*\b/ + 'parameter': [ + { + pattern: /(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/, + lookbehind: true, + inside: Prism.languages.javascript + }, + { + pattern: /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i, + inside: Prism.languages.javascript + }, + { + pattern: /(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/, + lookbehind: true, + inside: Prism.languages.javascript + }, + { + pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/, + lookbehind: true, + inside: Prism.languages.javascript + } + ], + 'constant': /\b[A-Z](?:[A-Z_]|\dx?)*\b/ }); Prism.languages.insertBefore('javascript', 'string', { @@ -32,25 +71,16 @@ Prism.languages.insertBefore('javascript', 'string', { pattern: /^\${|}$/, alias: 'punctuation' }, - rest: null // See below + rest: Prism.languages.javascript } }, 'string': /[\s\S]+/ } } }); -Prism.languages.javascript['template-string'].inside['interpolation'].inside.rest = Prism.languages.javascript; if (Prism.languages.markup) { - Prism.languages.insertBefore('markup', 'tag', { - 'script': { - pattern: /()[\s\S]*?(?=<\/script>)/i, - lookbehind: true, - inside: Prism.languages.javascript, - alias: 'language-javascript', - greedy: true - } - }); + Prism.languages.markup.tag.addInlined('script', 'javascript'); } Prism.languages.js = Prism.languages.javascript; diff --git a/kuma/static/js/libs/prism/prism-json.js b/kuma/static/js/libs/prism/prism-json.js index 06e847ec60e..5f4017913d6 100644 --- a/kuma/static/js/libs/prism/prism-json.js +++ b/kuma/static/js/libs/prism/prism-json.js @@ -1,14 +1,19 @@ Prism.languages.json = { - 'property': /"(?:\\.|[^\\"\r\n])*"(?=\s*:)/i, + 'comment': /\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/, + 'property': { + pattern: /"(?:\\.|[^\\"\r\n])*"(?=\s*:)/, + greedy: true + }, 'string': { pattern: /"(?:\\.|[^\\"\r\n])*"(?!\s*:)/, greedy: true }, - 'number': /\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/, - 'punctuation': /[{}[\]);,]/, - 'operator': /:/g, - 'boolean': /\b(?:true|false)\b/i, - 'null': /\bnull\b/i + 'number': /-?\d+\.?\d*(e[+-]?\d+)?/i, + 'punctuation': /[{}[\],]/, + 'operator': /:/, + 'boolean': /\b(?:true|false)\b/, + 'null': { + pattern: /\bnull\b/, + alias: 'keyword' + } }; - -Prism.languages.jsonp = Prism.languages.json; diff --git a/kuma/static/js/libs/prism/prism-jsonp.js b/kuma/static/js/libs/prism/prism-jsonp.js new file mode 100644 index 00000000000..c942015776c --- /dev/null +++ b/kuma/static/js/libs/prism/prism-jsonp.js @@ -0,0 +1,7 @@ +Prism.languages.jsonp = Prism.languages.extend('json', { + 'punctuation': /[{}[\]();,.]/ +}); + +Prism.languages.insertBefore('jsonp', 'punctuation', { + 'function': /[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/ +}); diff --git a/kuma/static/js/libs/prism/prism-line-numbers.js b/kuma/static/js/libs/prism/prism-line-numbers.js index e9e684fe944..7ab1dc046b8 100644 --- a/kuma/static/js/libs/prism/prism-line-numbers.js +++ b/kuma/static/js/libs/prism/prism-line-numbers.js @@ -9,7 +9,7 @@ * @type {String} */ var PLUGIN_NAME = 'line-numbers'; - + /** * Regular expression used for determining line breaks * @type {RegExp} @@ -71,28 +71,38 @@ return; } + var code = env.element; + var pre = code.parentNode; + // works only for wrapped inside
 (not inline)
-		var pre = env.element.parentNode;
-		var clsReg = /\s*\bline-numbers\b\s*/;
-		if (
-			!pre || !/pre/i.test(pre.nodeName) ||
-			// Abort only if nor the 
 nor the  have the class
-			(!clsReg.test(pre.className) && !clsReg.test(env.element.className))
-		) {
+		if (!pre || !/pre/i.test(pre.nodeName)) {
 			return;
 		}
 
-		if (env.element.querySelector('.line-numbers-rows')) {
-			// Abort if line numbers already exists
+		// Abort if line numbers already exists
+		if (code.querySelector('.line-numbers-rows')) {
 			return;
 		}
 
-		if (clsReg.test(env.element.className)) {
-			// Remove the class 'line-numbers' from the 
-			env.element.className = env.element.className.replace(clsReg, ' ');
+		var addLineNumbers = false;
+		var lineNumbersRegex = /(?:^|\s)line-numbers(?:\s|$)/;
+
+		for (var element = code; element; element = element.parentNode) {
+			if (lineNumbersRegex.test(element.className)) {
+				addLineNumbers = true;
+				break;
+			}
 		}
-		if (!clsReg.test(pre.className)) {
-			// Add the class 'line-numbers' to the 
+
+		// only add line numbers if  or one of its ancestors has the `line-numbers` class
+		if (!addLineNumbers) {
+			return;
+		}
+
+		// Remove the class 'line-numbers' from the 
+		code.className = code.className.replace(lineNumbersRegex, ' ');
+		// Add the class 'line-numbers' to the 
+		if (!lineNumbersRegex.test(pre.className)) {
 			pre.className += ' line-numbers';
 		}
 
@@ -100,8 +110,7 @@
 		var linesNum = match ? match.length + 1 : 1;
 		var lineNumbersWrapper;
 
-		var lines = new Array(linesNum + 1);
-		lines = lines.join('');
+		var lines = new Array(linesNum + 1).join('');
 
 		lineNumbersWrapper = document.createElement('span');
 		lineNumbersWrapper.setAttribute('aria-hidden', 'true');
@@ -123,7 +132,7 @@
 		env.plugins = env.plugins || {};
 		env.plugins.lineNumbers = true;
 	});
-	
+
 	/**
 	 * Global exports
 	 */
@@ -156,4 +165,4 @@
 		}
 	};
 
-}());
\ No newline at end of file
+}());
diff --git a/kuma/static/js/libs/prism/prism-markup.js b/kuma/static/js/libs/prism/prism-markup.js
index 7e4fa0c85ac..c288778fd2a 100644
--- a/kuma/static/js/libs/prism/prism-markup.js
+++ b/kuma/static/js/libs/prism/prism-markup.js
@@ -4,7 +4,7 @@ Prism.languages.markup = {
 	'doctype': //i,
 	'cdata': //i,
 	'tag': {
-		pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,
+		pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/i,
 		greedy: true,
 		inside: {
 			'tag': {
@@ -15,12 +15,12 @@ Prism.languages.markup = {
 				}
 			},
 			'attr-value': {
-				pattern: /=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i,
+				pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/i,
 				inside: {
 					'punctuation': [
 						/^=/,
 						{
-							pattern: /(^|[^\\])["']/,
+							pattern: /^(\s*)["']|["']$/,
 							lookbehind: true
 						}
 					]
@@ -50,7 +50,51 @@ Prism.hooks.add('wrap', function(env) {
 	}
 });
 
-Prism.languages.xml = Prism.languages.markup;
+Object.defineProperty(Prism.languages.markup.tag, 'addInlined', {
+	/**
+	 * Adds an inlined language to markup.
+	 *
+	 * An example of an inlined language is CSS with `