| 1 | ; |
| 2 | |
| 3 | // Extra highlight.js grammars for RDF formats that ship in this repository |
| 4 | // (Turtle and SPARQL) plus the file-extension → language table. |
| 5 | |
| 6 | const IRI = { scope: 'link', begin: /<[^<>"{}|^`\\\s]*>/ }; |
| 7 | const BLANK_NODE = { scope: 'variable', begin: /_:[\w.-]+/ }; |
| 8 | const LANG_TAG = { scope: 'meta', begin: /@[a-zA-Z]+(?:-[a-zA-Z0-9]+)*/ }; |
| 9 | const DATATYPE_CARET = { scope: 'punctuation', begin: /\^\^/ }; |
| 10 | const NUMBER = { scope: 'number', begin: /[+-]?\b\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b/, relevance: 0 }; |
| 11 | const PREFIXED_NAME = { |
| 12 | // prefix:local — prefix dimmed, local name coloured as a class/term. |
| 13 | begin: [/(?:[A-Za-z_][\w.-]*)?/, /:/, /[\w.\-%]+/], |
| 14 | beginScope: { 1: 'built_in', 2: 'punctuation', 3: 'title.class' }, |
| 15 | relevance: 0, |
| 16 | }; |
| 17 | |
| 18 | function stringModes(hljs) { |
| 19 | return [ |
| 20 | { scope: 'string', begin: /"""/, end: /"""/, contains: [hljs.BACKSLASH_ESCAPE] }, |
| 21 | { scope: 'string', begin: /'''/, end: /'''/, contains: [hljs.BACKSLASH_ESCAPE] }, |
| 22 | { scope: 'string', begin: /"/, end: /"/, illegal: /\n/, contains: [hljs.BACKSLASH_ESCAPE] }, |
| 23 | { scope: 'string', begin: /'/, end: /'/, illegal: /\n/, contains: [hljs.BACKSLASH_ESCAPE] }, |
| 24 | ]; |
| 25 | } |
| 26 | |
| 27 | function turtle(hljs) { |
| 28 | return { |
| 29 | name: 'Turtle', |
| 30 | aliases: ['ttl', 'n3', 'trig'], |
| 31 | contains: [ |
| 32 | hljs.HASH_COMMENT_MODE, |
| 33 | { scope: 'keyword', begin: /@(?:prefix|base)\b/ }, |
| 34 | { scope: 'keyword', begin: /\b(?:PREFIX|BASE)\b/ }, |
| 35 | { scope: 'keyword', begin: /\ba\b/ }, // rdf:type shorthand |
| 36 | { scope: 'literal', begin: /\b(?:true|false)\b/ }, |
| 37 | IRI, |
| 38 | ...stringModes(hljs), |
| 39 | DATATYPE_CARET, |
| 40 | LANG_TAG, |
| 41 | BLANK_NODE, |
| 42 | NUMBER, |
| 43 | PREFIXED_NAME, |
| 44 | { scope: 'punctuation', begin: /[;,.\[\]()]/ }, |
| 45 | ], |
| 46 | }; |
| 47 | } |
| 48 | |
| 49 | function sparql(hljs) { |
| 50 | const KEYWORDS = [ |
| 51 | 'SELECT', 'DISTINCT', 'REDUCED', 'WHERE', 'FILTER', 'OPTIONAL', 'UNION', 'GRAPH', 'FROM', |
| 52 | 'NAMED', 'PREFIX', 'BASE', 'ORDER', 'BY', 'ASC', 'DESC', 'LIMIT', 'OFFSET', 'GROUP', 'HAVING', |
| 53 | 'ASK', 'CONSTRUCT', 'DESCRIBE', 'BIND', 'VALUES', 'MINUS', 'SERVICE', 'AS', 'NOT', 'EXISTS', |
| 54 | 'IN', 'INSERT', 'DELETE', 'DATA', 'WITH', 'USING', 'LOAD', 'CLEAR', 'DROP', 'CREATE', 'ADD', |
| 55 | 'MOVE', 'COPY', 'SILENT', 'INTO', 'TO', 'ALL', 'DEFAULT', 'UNDEF', |
| 56 | ]; |
| 57 | const BUILTINS = [ |
| 58 | 'COUNT', 'SUM', 'MIN', 'MAX', 'AVG', 'SAMPLE', 'GROUP_CONCAT', 'SEPARATOR', 'STR', 'LANG', |
| 59 | 'LANGMATCHES', 'DATATYPE', 'BOUND', 'IRI', 'URI', 'BNODE', 'RAND', 'ABS', 'CEIL', 'FLOOR', |
| 60 | 'ROUND', 'CONCAT', 'STRLEN', 'UCASE', 'LCASE', 'ENCODE_FOR_URI', 'CONTAINS', 'STRSTARTS', |
| 61 | 'STRENDS', 'STRBEFORE', 'STRAFTER', 'YEAR', 'MONTH', 'DAY', 'HOURS', 'MINUTES', 'SECONDS', |
| 62 | 'TIMEZONE', 'TZ', 'NOW', 'UUID', 'STRUUID', 'MD5', 'SHA1', 'SHA256', 'SHA384', 'SHA512', |
| 63 | 'COALESCE', 'IF', 'STRLANG', 'STRDT', 'sameTerm', 'isIRI', 'isURI', 'isBLANK', 'isLITERAL', |
| 64 | 'isNUMERIC', 'REGEX', 'SUBSTR', 'REPLACE', |
| 65 | ]; |
| 66 | return { |
| 67 | name: 'SPARQL', |
| 68 | aliases: ['rq', 'sparql'], |
| 69 | case_insensitive: true, |
| 70 | keywords: { |
| 71 | $pattern: /[A-Za-z_][\w]*/, |
| 72 | keyword: KEYWORDS, |
| 73 | built_in: BUILTINS, |
| 74 | literal: ['true', 'false'], |
| 75 | }, |
| 76 | contains: [ |
| 77 | hljs.HASH_COMMENT_MODE, |
| 78 | { scope: 'variable', begin: /[?$][\w]+/ }, |
| 79 | { scope: 'keyword', begin: /\ba\b/ }, |
| 80 | IRI, |
| 81 | ...stringModes(hljs), |
| 82 | DATATYPE_CARET, |
| 83 | LANG_TAG, |
| 84 | BLANK_NODE, |
| 85 | NUMBER, |
| 86 | PREFIXED_NAME, |
| 87 | { scope: 'operator', begin: /&&|\|\||!=|<=|>=|[=<>!+\-*/]/ }, |
| 88 | { scope: 'punctuation', begin: /[{}()\[\];,.]/ }, |
| 89 | ], |
| 90 | }; |
| 91 | } |
| 92 | |
| 93 | /** file extension (lower case, without dot) → highlight.js language name */ |
| 94 | const EXT_LANG = { |
| 95 | py: 'python', |
| 96 | js: 'javascript', |
| 97 | mjs: 'javascript', |
| 98 | cjs: 'javascript', |
| 99 | ts: 'typescript', |
| 100 | json: 'json', |
| 101 | jsonl: 'json', |
| 102 | yaml: 'yaml', |
| 103 | yml: 'yaml', |
| 104 | ttl: 'turtle', |
| 105 | n3: 'turtle', |
| 106 | trig: 'turtle', |
| 107 | rq: 'sparql', |
| 108 | sparql: 'sparql', |
| 109 | sh: 'bash', |
| 110 | bash: 'bash', |
| 111 | zsh: 'bash', |
| 112 | html: 'xml', |
| 113 | htm: 'xml', |
| 114 | xml: 'xml', |
| 115 | svg: 'xml', |
| 116 | css: 'css', |
| 117 | md: 'markdown', |
| 118 | markdown: 'markdown', |
| 119 | toml: 'ini', |
| 120 | ini: 'ini', |
| 121 | cfg: 'ini', |
| 122 | env: 'bash', |
| 123 | txt: 'plaintext', |
| 124 | csv: 'plaintext', |
| 125 | tsv: 'plaintext', |
| 126 | log: 'plaintext', |
| 127 | sql: 'sql', |
| 128 | dockerfile: 'dockerfile', |
| 129 | makefile: 'makefile', |
| 130 | }; |
| 131 | |
| 132 | const FILENAME_LANG = { |
| 133 | dockerfile: 'dockerfile', |
| 134 | makefile: 'makefile', |
| 135 | '.gitignore': 'plaintext', |
| 136 | '.dockerignore': 'plaintext', |
| 137 | 'requirements.txt': 'plaintext', |
| 138 | }; |
| 139 | |
| 140 | function languageFor(filename) { |
| 141 | const lower = filename.toLowerCase(); |
| 142 | if (FILENAME_LANG[lower]) return FILENAME_LANG[lower]; |
| 143 | const idx = lower.lastIndexOf('.'); |
| 144 | if (idx === -1) return null; |
| 145 | return EXT_LANG[lower.slice(idx + 1)] || null; |
| 146 | } |
| 147 | |
| 148 | function registerLanguages(hljs) { |
| 149 | hljs.registerLanguage('turtle', turtle); |
| 150 | hljs.registerLanguage('sparql', sparql); |
| 151 | } |
| 152 | |
| 153 | module.exports = { registerLanguages, languageFor, EXT_LANG }; |