From 0889bc7c2a48804e72d45f499b837d865ef03ecf Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 4 Nov 2020 21:44:48 +0100 Subject: [PATCH] Java: Improved package and class name detection (#2599) --- components/prism-java.js | 52 +++++++---- components/prism-java.min.js | 2 +- tests/languages/java/annotation_feature.test | 32 +++++++ tests/languages/java/class-name_feature.test | 94 ++++++++++++++++++++ tests/languages/java/function_featrue.test | 4 +- tests/languages/java/generics_feature.test | 61 ++++++++++--- tests/languages/java/issue1351.test | 26 ++++-- tests/languages/java/module_feature.test | 20 +++-- tests/languages/java/package_feature.test | 30 ++++--- tests/languages/java/string_feature.test | 7 +- tests/languages/javadoc/code_feature.test | 75 +++++++++++----- 11 files changed, 322 insertions(+), 81 deletions(-) create mode 100644 tests/languages/java/annotation_feature.test create mode 100644 tests/languages/java/class-name_feature.test diff --git a/components/prism-java.js b/components/prism-java.js index f5b2bf70d1..2ebc693eee 100644 --- a/components/prism-java.js +++ b/components/prism-java.js @@ -2,22 +2,40 @@ var keywords = /\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/; + // full package (optional) + parent classes (optional) + var classNamePrefix = /(^|[^\w.])(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source; + // based on the java naming conventions - var className = /\b[A-Z](?:\w*[a-z]\w*)?\b/; + var className = { + pattern: RegExp(classNamePrefix + /[A-Z](?:\w*[a-z]\w*)?\b/.source), + lookbehind: true, + inside: { + 'namespace': { + pattern: /^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/, + inside: { + 'punctuation': /\./ + } + }, + 'punctuation': /\./ + } + }; Prism.languages.java = Prism.languages.extend('clike', { 'class-name': [ className, - - // variables and parameters - // this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods) - /\b[A-Z]\w*(?=\s+\w+\s*[;,=())])/ + { + // variables and parameters + // this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods) + pattern: RegExp(classNamePrefix + /[A-Z]\w*(?=\s+\w+\s*[;,=())])/.source), + lookbehind: true, + inside: className.inside + } ], 'keyword': keywords, 'function': [ Prism.languages.clike.function, { - pattern: /(\:\:)[a-z_]\w*/, + pattern: /(\:\:\s*)[a-z_]\w*/, lookbehind: true } ], @@ -39,18 +57,9 @@ Prism.languages.insertBefore('java', 'class-name', { 'annotation': { - alias: 'punctuation', - pattern: /(^|[^.])@\w+/, - lookbehind: true - }, - 'namespace': { - pattern: RegExp( - /(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/ - .source.replace(//g, function () { return keywords.source; })), + pattern: /(^|[^.])@\w+(?:\s*\.\s*\w+)*/, lookbehind: true, - inside: { - 'punctuation': /\./, - } + alias: 'punctuation' }, 'generics': { pattern: /<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/, @@ -60,6 +69,15 @@ 'punctuation': /[<>(),.:]/, 'operator': /[?&|]/ } + }, + 'namespace': { + pattern: RegExp( + /(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/ + .source.replace(//g, function () { return keywords.source; })), + lookbehind: true, + inside: { + 'punctuation': /\./, + } } }); }(Prism)); diff --git a/components/prism-java.min.js b/components/prism-java.min.js index 54e1d78e1c..cd6a09bd0b 100644 --- a/components/prism-java.min.js +++ b/components/prism-java.min.js @@ -1 +1 @@ -!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,a=/\b[A-Z](?:\w*[a-z]\w*)?\b/;e.languages.java=e.languages.extend("clike",{"class-name":[a,/\b[A-Z]\w*(?=\s+\w+\s*[;,=())])/],keyword:t,function:[e.languages.clike.function,{pattern:/(\:\:)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x[\da-f_]*\.?[\da-f_p+-]+\b|(?:\b\d[\d_]*\.?[\d_]*|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"}}),e.languages.insertBefore("java","class-name",{annotation:{alias:"punctuation",pattern:/(^|[^.])@\w+/,lookbehind:!0},namespace:{pattern:RegExp("(\\b(?:exports|import(?:\\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\\s+)(?!)[a-z]\\w*(?:\\.[a-z]\\w*)*\\.?".replace(//g,function(){return t.source})),lookbehind:!0,inside:{punctuation:/\./}},generics:{pattern:/<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,inside:{"class-name":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}}})}(Prism); \ No newline at end of file +!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n="(^|[^\\w.])(?:[a-z]\\w*\\s*\\.\\s*)*(?:[A-Z]\\w*\\s*\\.\\s*)*",a={pattern:RegExp(n+"[A-Z](?:\\w*[a-z]\\w*)?\\b"),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{"class-name":[a,{pattern:RegExp(n+"[A-Z]\\w*(?=\\s+\\w+\\s*[;,=())])"),lookbehind:!0,inside:a.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(\:\:\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x[\da-f_]*\.?[\da-f_p+-]+\b|(?:\b\d[\d_]*\.?[\d_]*|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,inside:{"class-name":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},namespace:{pattern:RegExp("(\\b(?:exports|import(?:\\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\\s+)(?!)[a-z]\\w*(?:\\.[a-z]\\w*)*\\.?".replace(//g,function(){return t.source})),lookbehind:!0,inside:{punctuation:/\./}}})}(Prism); \ No newline at end of file diff --git a/tests/languages/java/annotation_feature.test b/tests/languages/java/annotation_feature.test new file mode 100644 index 0000000000..3c645542c8 --- /dev/null +++ b/tests/languages/java/annotation_feature.test @@ -0,0 +1,32 @@ +@Override +@Documented +@java.long.annotation.Documented + +@Retention(value=SOURCE) +@Target(value={PACKAGE,TYPE}) + +---------------------------------------------------- + +[ + ["annotation", "@Override"], + ["annotation", "@Documented"], + ["annotation", "@java.long.annotation.Documented"], + + ["annotation", "@Retention"], + ["punctuation", "("], + "value", + ["operator", "="], + "SOURCE", + ["punctuation", ")"], + + ["annotation", "@Target"], + ["punctuation", "("], + "value", + ["operator", "="], + ["punctuation", "{"], + "PACKAGE", + ["punctuation", ","], + "TYPE", + ["punctuation", "}"], + ["punctuation", ")"] +] diff --git a/tests/languages/java/class-name_feature.test b/tests/languages/java/class-name_feature.test new file mode 100644 index 0000000000..a5929a721c --- /dev/null +++ b/tests/languages/java/class-name_feature.test @@ -0,0 +1,94 @@ +class Foo extends foo.bar.Foo { + + java.util.List bar(foo.bar.Baz bat) throws java.lang.IOException { + throw new java.lang.UnsupportedOperationException("Not implemented"); + } + +} + +---------------------------------------------------- + +[ + ["keyword", "class"], + ["class-name", [ + "Foo" + ]], + ["keyword", "extends"], + ["class-name", [ + ["namespace", [ + "foo", + ["punctuation", "."], + "bar", + ["punctuation", "."] + ]], + "Foo" + ]], + ["punctuation", "{"], + + ["class-name", [ + ["namespace", [ + "java", + ["punctuation", "."], + "util", + ["punctuation", "."] + ]], + "List" + ]], + ["generics", [ + ["punctuation", "<"], + ["class-name", [ + ["namespace", [ + "foo", + ["punctuation", "."], + "bar", + ["punctuation", "."] + ]], + "Foo", + ["punctuation", "."], + "Bar" + ]], + ["punctuation", ">"] + ]], + ["function", "bar"], + ["punctuation", "("], + ["class-name", [ + ["namespace", [ + "foo", + ["punctuation", "."], + "bar", + ["punctuation", "."] + ]], + "Baz" + ]], + " bat", + ["punctuation", ")"], + ["keyword", "throws"], + ["class-name", [ + ["namespace", [ + "java", + ["punctuation", "."], + "lang", + ["punctuation", "."] + ]], + "IOException" + ]], + ["punctuation", "{"], + ["keyword", "throw"], + ["keyword", "new"], + ["class-name", [ + ["namespace", [ + "java", + ["punctuation", "."], + "lang", + ["punctuation", "."] + ]], + "UnsupportedOperationException" + ]], + ["punctuation", "("], + ["string", "\"Not implemented\""], + ["punctuation", ")"], + ["punctuation", ";"], + ["punctuation", "}"], + + ["punctuation", "}"] +] diff --git a/tests/languages/java/function_featrue.test b/tests/languages/java/function_featrue.test index 065e2c3e1c..d54e5941ec 100644 --- a/tests/languages/java/function_featrue.test +++ b/tests/languages/java/function_featrue.test @@ -20,7 +20,9 @@ Bar::foo; ["punctuation", ")"], ["punctuation", ";"], - ["class-name", "Bar"], + ["class-name", [ + "Bar" + ]], ["operator", "::"], ["function", "foo"], ["punctuation", ";"] diff --git a/tests/languages/java/generics_feature.test b/tests/languages/java/generics_feature.test index d1d5e5363a..12d9fb6231 100644 --- a/tests/languages/java/generics_feature.test +++ b/tests/languages/java/generics_feature.test @@ -1,5 +1,5 @@ -public class Solo {} -Solo val = new Solo(); +public class Solo {} +Solo val = new Solo<>(); Duo dual = new Duo(12.2585, 'C'); ---------------------------------------------------- @@ -7,51 +7,84 @@ Duo dual = new Duo(12.2585, 'C'); [ ["keyword", "public"], ["keyword", "class"], - ["class-name", "Solo"], + ["class-name", [ + "Solo" + ]], ["generics", [ ["punctuation", "<"], - ["class-name", "T"], + ["class-name", [ + "T" + ]], + ["keyword", "extends"], + ["class-name", [ + ["namespace", [ + "com", + ["punctuation", "."], + "foo", + ["punctuation", "."] + ]], + "Foo", + ["punctuation", "."], + "Bar" + ]], ["punctuation", ">"] ]], ["punctuation", "{"], ["punctuation", "}"], - ["class-name", "Solo"], + ["class-name", [ + "Solo" + ]], ["generics", [ ["punctuation", "<"], - ["class-name", "Integer"], + ["class-name", [ + "Integer" + ]], ["punctuation", ">"] ]], " val ", ["operator", "="], ["keyword", "new"], - ["class-name", "Solo"], + ["class-name", [ + "Solo" + ]], ["generics", [ ["punctuation", "<"], - ["class-name", "Integer"], ["punctuation", ">"] ]], ["punctuation", "("], ["punctuation", ")"], ["punctuation", ";"], - ["class-name", "Duo"], + ["class-name", [ + "Duo" + ]], ["generics", [ ["punctuation", "<"], - ["class-name", "Double"], + ["class-name", [ + "Double" + ]], ["punctuation", ","], - ["class-name", "Character"], + ["class-name", [ + "Character" + ]], ["punctuation", ">"] ]], " dual ", ["operator", "="], ["keyword", "new"], - ["class-name", "Duo"], + ["class-name", [ + "Duo" + ]], ["generics", [ ["punctuation", "<"], - ["class-name", "Double"], + ["class-name", [ + "Double" + ]], ["punctuation", ","], - ["class-name", "Character"], + ["class-name", [ + "Character" + ]], ["punctuation", ">"] ]], ["punctuation", "("], diff --git a/tests/languages/java/issue1351.test b/tests/languages/java/issue1351.test index 3034e3e857..4bb0817d26 100644 --- a/tests/languages/java/issue1351.test +++ b/tests/languages/java/issue1351.test @@ -5,18 +5,28 @@ public class AllChangesIndexer extends SiteIndexer"] ]], ["punctuation", "{"] @@ -24,4 +34,4 @@ public class AllChangesIndexer extends SiteIndexer"] ]], + "\r\n * ", ["tag", [ ["tag", [ @@ -104,7 +105,7 @@ ["code-section", [ ["line", [ ["code", [ - ["class-name", "Foo"] + ["class-name", ["Foo"]] ]] ]] ]], @@ -115,6 +116,7 @@ ]], ["punctuation", ">"] ]], + "\r\n *\r\n * ", ["tag", [ ["tag", [ @@ -130,6 +132,7 @@ ]], ["punctuation", ">"] ]], + ["code-section", [ "* ", ["line", [ @@ -153,6 +156,7 @@ ["punctuation", "{"] ]] ]], + "\r\n * ", ["line", [ ["code", [ @@ -165,12 +169,14 @@ ["punctuation", ";"] ]] ]], + "\r\n * ", ["line", [ ["code", [ ["punctuation", "}"] ]] ]], + "\r\n * ", ["line", [ ["code", [ @@ -179,6 +185,7 @@ ["punctuation", ";"] ]] ]], + "\r\n *" ]], ["tag", [ @@ -195,6 +202,7 @@ ]], ["punctuation", ">"] ]], + "\r\n *\r\n * ", ["tag", [ ["tag", [ @@ -205,13 +213,14 @@ ]], ["punctuation", "{"], ["keyword", "@code"], + ["code-section", [ "* ", ["code", [ - ["class-name", "String"], + ["class-name", ["String"]], " message ", ["operator", "="], - ["class-name", "String"], + ["class-name", ["String"]], ["punctuation", "."], ["function", "join"], ["punctuation", "("], @@ -225,10 +234,12 @@ ["punctuation", ")"], ["punctuation", ";"] ]], + "\r\n * ", ["code", [ ["comment", "// message returned is: \"Java-is-cool\""] ]], + "\r\n *" ]], ["punctuation", "}"], @@ -239,6 +250,7 @@ ]], ["punctuation", ">"] ]], + "\r\n *\r\n * ", ["tag", [ ["tag", [ @@ -247,6 +259,7 @@ ]], ["punctuation", ">"] ]], + ["code-section", [ "* ", ["line", [ @@ -262,6 +275,7 @@ ["number", "1"] ]] ]], + "\r\n *" ]], ["tag", [ @@ -271,6 +285,7 @@ ]], ["punctuation", ">"] ]], + "\r\n *\r\n * ", ["tag", [ ["tag", [ @@ -279,6 +294,7 @@ ]], ["punctuation", ">"] ]], + ["code-section", [ "* ", ["line", [ @@ -296,9 +312,7 @@ ]], ["punctuation", ">"] ]], - ["code", [ - "c" - ]], + ["code", ["c"]], ["tag", [ ["tag", [ ["punctuation", ""] ]], - ["code", [ - "b" - ]], + ["code", ["b"]], ["tag", [ ["tag", [ ["punctuation", ""] ]], + "\r\n *\r\n * ", ["tag", [ ["tag", [ @@ -400,53 +415,59 @@ ]], ["punctuation", "{"], ["keyword", "@code"], + ["code-section", [ "* ", ["code", [ ["keyword", "interface"], - ["class-name", "ArchiveSearcher"], + ["class-name", ["ArchiveSearcher"]], ["punctuation", "{"], - ["class-name", "String"], + ["class-name", ["String"]], ["function", "search"], ["punctuation", "("], - ["class-name", "String"], + ["class-name", ["String"]], " target", ["punctuation", ")"], ["punctuation", ";"], ["punctuation", "}"] ]], + "\r\n * ", ["code", [ ["keyword", "class"], - ["class-name", "App"], + ["class-name", ["App"]], ["punctuation", "{"] ]], + "\r\n * ", ["code", [ ["keyword", "void"], ["function", "showSearch"], ["punctuation", "("], ["keyword", "final"], - ["class-name", "String"], + ["class-name", ["String"]], " target", ["punctuation", ")"] ]], + "\r\n * ", ["code", [ ["keyword", "throws"], - ["class-name", "InterruptedException"], + ["class-name", ["InterruptedException"]], ["punctuation", "{"] ]], + "\r\n * ", ["code", [ - ["class-name", "Future"], + ["class-name", ["Future"]], ["generics", [ ["punctuation", "<"], - ["class-name", "String"], + ["class-name", ["String"]], ["punctuation", ">"] ]], " future" ]], + "\r\n * ", ["code", [ ["operator", "="], @@ -455,25 +476,27 @@ ["function", "submit"], ["punctuation", "("], ["keyword", "new"], - ["class-name", "Callable"], + ["class-name", ["Callable"]], ["generics", [ ["punctuation", "<"], - ["class-name", "String"], + ["class-name", ["String"]], ["punctuation", ">"] ]], ["punctuation", "("], ["punctuation", ")"], ["punctuation", "{"] ]], + "\r\n * ", ["code", [ ["keyword", "public"], - ["class-name", "String"], + ["class-name", ["String"]], ["function", "call"], ["punctuation", "("], ["punctuation", ")"], ["punctuation", "{"] ]], + "\r\n * ", ["code", [ ["keyword", "return"], @@ -485,6 +508,7 @@ ["punctuation", ")"], ["punctuation", ";"] ]], + "\r\n * ", ["code", [ ["punctuation", "}"], @@ -492,6 +516,7 @@ ["punctuation", ")"], ["punctuation", ";"] ]], + "\r\n * ", ["code", [ ["function", "displayOtherThings"], @@ -500,11 +525,13 @@ ["punctuation", ";"], ["comment", "// do other things while searching"] ]], + "\r\n * ", ["code", [ ["keyword", "try"], ["punctuation", "{"] ]], + "\r\n * ", ["code", [ ["function", "displayText"], @@ -518,12 +545,13 @@ ["punctuation", ";"], ["comment", "// use future"] ]], + "\r\n * ", ["code", [ ["punctuation", "}"], ["keyword", "catch"], ["punctuation", "("], - ["class-name", "ExecutionException"], + ["class-name", ["ExecutionException"]], " ex", ["punctuation", ")"], ["punctuation", "{"], @@ -535,10 +563,12 @@ ["punctuation", ";"], ["punctuation", "}"] ]], + "\r\n * ", ["code", [ ["punctuation", "}"] ]], + "\r\n * ", ["code", [ ["punctuation", "}"] @@ -552,6 +582,7 @@ ]], ["punctuation", ">"] ]], + "\r\n */" ]