├── .gitignore
├── LICENSE
├── README.md
├── img
└── Contract-example.png
├── package.json
└── src
├── ContractViewer.js
├── Highlight.js
└── highlight.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, Daniel Novy
2 | All rights reserved.
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are met:
5 |
6 | * Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | * Redistributions in binary form must reproduce the above copyright
9 | notice, this list of conditions and the following disclaimer in the
10 | documentation and/or other materials provided with the distribution.
11 | * Neither the name of highlight.js nor the names of its contributors
12 | may be used to endorse or promote products derived from this software
13 | without specific prior written permission.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
16 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Solidity Contract Viewer
2 |
3 | This module simplifies the process of showing a Solidity Contract in a webpage
4 | beautified with syntax highlight and code indentation. Dynamic changes on the
5 | underline contract properties are reflected imediatly in the contract code shown
6 | on the webpage.
7 |
8 | It uses a modified version of [highlight-js](https://github.com/isagalaev/highlight.js)
9 | adapted to handle solidity code.
10 |
11 | As in the highlight-js library, different styles can be applied by simple adding
12 | the desired style in the main html file. Styles can be downloaded from
13 | [here](https://github.com/isagalaev/highlight.js/tree/master/src/styles).
14 |
15 | # IMPORTANT WARNING
16 |
17 | Because of a limitation in React, the react version used in this library (0.12.2) should
18 | matches the version used in your project! Otherwise, you will get the message below
19 | when running your code:
20 |
21 | ```
22 | EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely
23 | trying to load more than one copy of React.
24 | ```
25 |
26 | As the message says, if you run two distinct version for your code and for this library,
27 | the React library will be loaded twice in your app and you will get the message above.
28 |
29 | # Install
30 |
31 | To install this module globally, just type `sudo npm install contract-viewer -g`.
32 |
33 | # Usage example
34 |
35 | This module works using contract templates. You basically have define a contract
36 | template as a js module, as in:
37 |
38 | ```javascript
39 | var mycontracttemplate = '\n\
40 | contract ui_contract_name {\n\
41 | bytes32 ui_string1_name = "ui_string1_value";\n\
42 | function ui_function1_name(bytes32 value) {\n\
43 | ui_string1_name = value;\n\
44 | }\n\
45 | }';
46 | module.exports = mycontracttemplate;
47 | ```
48 |
49 | After defining your contract template, you `require` it in the react component
50 | where you are using the contractviewer. You will notice that there are some placeholders
51 | in the contract template. In our case, all words starting with `ui_` is a placeholder.
52 | these are the dynamic parts of the contract. When you use the contractviewer, you
53 | link these placeholders using `state` variables of the react component so that whenever
54 | the state change, the contract is automatically updated in the webpage. See example
55 | below:
56 |
57 | ```javascript
58 | var MyTemplate = require('../data/MyContractTemplate.sol.js');
59 | var ContractViewer = require('contract-viewer');
60 |
61 | var myapp = react.createclass({
62 | getinitialstate: function() {
63 | return {
64 | contractName : 'MyContract',
65 | string1Name : 'customerName',
66 | string1Value : 'Satoshi Nakamoto',
67 | function1Name: 'setCustomerName'
68 | };
69 | },
70 | onChangeCode: function(contractCode) {
71 | // Result contract code is stored on param 'contractCode'
72 | },
73 | render: function() {
74 | return
75 |
{this.props.children}
;
35 | }
36 | });
37 |
38 | module.exports = Highlight;
39 |
--------------------------------------------------------------------------------
/src/highlight.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | highlight-js library pack
4 |
5 | Copyright (c) 2006, Ivan Sagalaev
6 | All rights reserved.
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | * Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 | * Neither the name of highlight.js nor the names of its contributors
16 | may be used to endorse or promote products derived from this software
17 | without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | */
31 |
32 | (function(factory) {
33 |
34 | // Setup highlight.js for different environments. First is Node.js or
35 | // CommonJS.
36 | if(typeof exports !== 'undefined') {
37 | factory(exports);
38 | } else {
39 | // Export hljs globally even when using AMD for cases when this script
40 | // is loaded with others that may still expect a global hljs.
41 | window.hljs = factory({});
42 |
43 | // Finally register the global hljs with AMD.
44 | if(typeof define === 'function' && define.amd) {
45 | define('hljs', [], function() {
46 | return window.hljs;
47 | });
48 | }
49 | }
50 |
51 | }(function(hljs) {
52 |
53 | /* Utility functions */
54 |
55 | function escape(value) {
56 | return value.replace(/&/gm, '&').replace(//gm, '>');
57 | }
58 |
59 | function tag(node) {
60 | return node.nodeName.toLowerCase();
61 | }
62 |
63 | function testRe(re, lexeme) {
64 | var match = re && re.exec(lexeme);
65 | return match && match.index == 0;
66 | }
67 |
68 | function isNotHighlighted(language) {
69 | return /^(no-?highlight|plain|text)$/.test(language);
70 | }
71 |
72 | function blockLanguage(block) {
73 | var i, match, length,
74 | classes = block.className + ' ';
75 |
76 | classes += block.parentNode ? block.parentNode.className : '';
77 |
78 | // language-* takes precedence over non-prefixed class names and
79 | match = /\blang(?:uage)?-([\w-]+)\b/.exec(classes);
80 | if (match) {
81 | return getLanguage(match[1]) ? match[1] : 'no-highlight';
82 | }
83 |
84 | classes = classes.split(/\s+/);
85 | for(i = 0, length = classes.length; i < length; i++) {
86 | if(getLanguage(classes[i]) || isNotHighlighted(classes[i])) {
87 | return classes[i];
88 | }
89 | }
90 |
91 | }
92 |
93 | function inherit(parent, obj) {
94 | var result = {}, key;
95 | for (key in parent)
96 | result[key] = parent[key];
97 | if (obj)
98 | for (key in obj)
99 | result[key] = obj[key];
100 | return result;
101 | }
102 |
103 | /* Stream merging */
104 |
105 | function nodeStream(node) {
106 | var result = [];
107 | (function _nodeStream(node, offset) {
108 | for (var child = node.firstChild; child; child = child.nextSibling) {
109 | if (child.nodeType == 3)
110 | offset += child.nodeValue.length;
111 | else if (child.nodeType == 1) {
112 | result.push({
113 | event: 'start',
114 | offset: offset,
115 | node: child
116 | });
117 | offset = _nodeStream(child, offset);
118 | // Prevent void elements from having an end tag that would actually
119 | // double them in the output. There are more void elements in HTML
120 | // but we list only those realistically expected in code display.
121 | if (!tag(child).match(/br|hr|img|input/)) {
122 | result.push({
123 | event: 'stop',
124 | offset: offset,
125 | node: child
126 | });
127 | }
128 | }
129 | }
130 | return offset;
131 | })(node, 0);
132 | return result;
133 | }
134 |
135 | function mergeStreams(original, highlighted, value) {
136 | var processed = 0;
137 | var result = '';
138 | var nodeStack = [];
139 |
140 | function selectStream() {
141 | if (!original.length || !highlighted.length) {
142 | return original.length ? original : highlighted;
143 | }
144 | if (original[0].offset != highlighted[0].offset) {
145 | return (original[0].offset < highlighted[0].offset) ? original : highlighted;
146 | }
147 |
148 | /*
149 | To avoid starting the stream just before it should stop the order is
150 | ensured that original always starts first and closes last:
151 |
152 | if (event1 == 'start' && event2 == 'start')
153 | return original;
154 | if (event1 == 'start' && event2 == 'stop')
155 | return highlighted;
156 | if (event1 == 'stop' && event2 == 'start')
157 | return original;
158 | if (event1 == 'stop' && event2 == 'stop')
159 | return highlighted;
160 |
161 | ... which is collapsed to:
162 | */
163 | return highlighted[0].event == 'start' ? original : highlighted;
164 | }
165 |
166 | function open(node) {
167 | function attr_str(a) {return ' ' + a.nodeName + '="' + escape(a.value) + '"';}
168 | result += '<' + tag(node) + Array.prototype.map.call(node.attributes, attr_str).join('') + '>';
169 | }
170 |
171 | function close(node) {
172 | result += '' + tag(node) + '>';
173 | }
174 |
175 | function render(event) {
176 | (event.event == 'start' ? open : close)(event.node);
177 | }
178 |
179 | while (original.length || highlighted.length) {
180 | var stream = selectStream();
181 | result += escape(value.substr(processed, stream[0].offset - processed));
182 | processed = stream[0].offset;
183 | if (stream == original) {
184 | /*
185 | On any opening or closing tag of the original markup we first close
186 | the entire highlighted node stack, then render the original tag along
187 | with all the following original tags at the same offset and then
188 | reopen all the tags on the highlighted stack.
189 | */
190 | nodeStack.reverse().forEach(close);
191 | do {
192 | render(stream.splice(0, 1)[0]);
193 | stream = selectStream();
194 | } while (stream == original && stream.length && stream[0].offset == processed);
195 | nodeStack.reverse().forEach(open);
196 | } else {
197 | if (stream[0].event == 'start') {
198 | nodeStack.push(stream[0].node);
199 | } else {
200 | nodeStack.pop();
201 | }
202 | render(stream.splice(0, 1)[0]);
203 | }
204 | }
205 | return result + escape(value.substr(processed));
206 | }
207 |
208 | /* Initialization */
209 |
210 | function compileLanguage(language) {
211 |
212 | function reStr(re) {
213 | return (re && re.source) || re;
214 | }
215 |
216 | function langRe(value, global) {
217 | return new RegExp(
218 | reStr(value),
219 | 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '')
220 | );
221 | }
222 |
223 | function compileMode(mode, parent) {
224 | if (mode.compiled)
225 | return;
226 | mode.compiled = true;
227 |
228 | mode.keywords = mode.keywords || mode.beginKeywords;
229 | if (mode.keywords) {
230 | var compiled_keywords = {};
231 |
232 | var flatten = function(className, str) {
233 | if (language.case_insensitive) {
234 | str = str.toLowerCase();
235 | }
236 | str.split(' ').forEach(function(kw) {
237 | var pair = kw.split('|');
238 | compiled_keywords[pair[0]] = [className, pair[1] ? Number(pair[1]) : 1];
239 | });
240 | };
241 |
242 | if (typeof mode.keywords == 'string') { // string
243 | flatten('keyword', mode.keywords);
244 | } else {
245 | Object.keys(mode.keywords).forEach(function (className) {
246 | flatten(className, mode.keywords[className]);
247 | });
248 | }
249 | mode.keywords = compiled_keywords;
250 | }
251 | mode.lexemesRe = langRe(mode.lexemes || /\b\w+\b/, true);
252 |
253 | if (parent) {
254 | if (mode.beginKeywords) {
255 | mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')\\b';
256 | }
257 | if (!mode.begin)
258 | mode.begin = /\B|\b/;
259 | mode.beginRe = langRe(mode.begin);
260 | if (!mode.end && !mode.endsWithParent)
261 | mode.end = /\B|\b/;
262 | if (mode.end)
263 | mode.endRe = langRe(mode.end);
264 | mode.terminator_end = reStr(mode.end) || '';
265 | if (mode.endsWithParent && parent.terminator_end)
266 | mode.terminator_end += (mode.end ? '|' : '') + parent.terminator_end;
267 | }
268 | if (mode.illegal)
269 | mode.illegalRe = langRe(mode.illegal);
270 | if (mode.relevance === undefined)
271 | mode.relevance = 1;
272 | if (!mode.contains) {
273 | mode.contains = [];
274 | }
275 | var expanded_contains = [];
276 | mode.contains.forEach(function(c) {
277 | if (c.variants) {
278 | c.variants.forEach(function(v) {expanded_contains.push(inherit(c, v));});
279 | } else {
280 | expanded_contains.push(c == 'self' ? mode : c);
281 | }
282 | });
283 | mode.contains = expanded_contains;
284 | mode.contains.forEach(function(c) {compileMode(c, mode);});
285 |
286 | if (mode.starts) {
287 | compileMode(mode.starts, parent);
288 | }
289 |
290 | var terminators =
291 | mode.contains.map(function(c) {
292 | return c.beginKeywords ? '\\.?(' + c.begin + ')\\.?' : c.begin;
293 | })
294 | .concat([mode.terminator_end, mode.illegal])
295 | .map(reStr)
296 | .filter(Boolean);
297 | mode.terminators = terminators.length ? langRe(terminators.join('|'), true) : {exec: function(/*s*/) {return null;}};
298 | }
299 |
300 | compileMode(language);
301 | }
302 |
303 | /*
304 | Core highlighting function. Accepts a language name, or an alias, and a
305 | string with the code to highlight. Returns an object with the following
306 | properties:
307 |
308 | - relevance (int)
309 | - value (an HTML string with highlighting markup)
310 |
311 | */
312 | function highlight(name, value, ignore_illegals, continuation) {
313 |
314 | function subMode(lexeme, mode) {
315 | for (var i = 0; i < mode.contains.length; i++) {
316 | if (testRe(mode.contains[i].beginRe, lexeme)) {
317 | return mode.contains[i];
318 | }
319 | }
320 | }
321 |
322 | function endOfMode(mode, lexeme) {
323 | if (testRe(mode.endRe, lexeme)) {
324 | while (mode.endsParent && mode.parent) {
325 | mode = mode.parent;
326 | }
327 | return mode;
328 | }
329 | if (mode.endsWithParent) {
330 | return endOfMode(mode.parent, lexeme);
331 | }
332 | }
333 |
334 | function isIllegal(lexeme, mode) {
335 | return !ignore_illegals && testRe(mode.illegalRe, lexeme);
336 | }
337 |
338 | function keywordMatch(mode, match) {
339 | var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0];
340 | return mode.keywords.hasOwnProperty(match_str) && mode.keywords[match_str];
341 | }
342 |
343 | function buildSpan(classname, insideSpan, leaveOpen, noPrefix) {
344 | var classPrefix = noPrefix ? '' : options.classPrefix,
345 | openSpan = '';
349 |
350 | return openSpan + insideSpan + closeSpan;
351 | }
352 |
353 | function processKeywords() {
354 | if (!top.keywords)
355 | return escape(mode_buffer);
356 | var result = '';
357 | var last_index = 0;
358 | top.lexemesRe.lastIndex = 0;
359 | var match = top.lexemesRe.exec(mode_buffer);
360 | while (match) {
361 | result += escape(mode_buffer.substr(last_index, match.index - last_index));
362 | var keyword_match = keywordMatch(top, match);
363 | if (keyword_match) {
364 | relevance += keyword_match[1];
365 | result += buildSpan(keyword_match[0], escape(match[0]));
366 | } else {
367 | result += escape(match[0]);
368 | }
369 | last_index = top.lexemesRe.lastIndex;
370 | match = top.lexemesRe.exec(mode_buffer);
371 | }
372 | return result + escape(mode_buffer.substr(last_index));
373 | }
374 |
375 | function processSubLanguage() {
376 | var explicit = typeof top.subLanguage == 'string';
377 | if (explicit && !languages[top.subLanguage]) {
378 | return escape(mode_buffer);
379 | }
380 |
381 | var result = explicit ?
382 | highlight(top.subLanguage, mode_buffer, true, continuations[top.subLanguage]) :
383 | highlightAuto(mode_buffer, top.subLanguage.length ? top.subLanguage : undefined);
384 |
385 | // Counting embedded language score towards the host language may be disabled
386 | // with zeroing the containing mode relevance. Usecase in point is Markdown that
387 | // allows XML everywhere and makes every XML snippet to have a much larger Markdown
388 | // score.
389 | if (top.relevance > 0) {
390 | relevance += result.relevance;
391 | }
392 | if (explicit) {
393 | continuations[top.subLanguage] = result.top;
394 | }
395 | return buildSpan(result.language, result.value, false, true);
396 | }
397 |
398 | function processBuffer() {
399 | return top.subLanguage !== undefined ? processSubLanguage() : processKeywords();
400 | }
401 |
402 | function startNewMode(mode, lexeme) {
403 | var markup = mode.className? buildSpan(mode.className, '', true): '';
404 | if (mode.returnBegin) {
405 | result += markup;
406 | mode_buffer = '';
407 | } else if (mode.excludeBegin) {
408 | result += escape(lexeme) + markup;
409 | mode_buffer = '';
410 | } else {
411 | result += markup;
412 | mode_buffer = lexeme;
413 | }
414 | top = Object.create(mode, {parent: {value: top}});
415 | }
416 |
417 | function processLexeme(buffer, lexeme) {
418 |
419 | mode_buffer += buffer;
420 | if (lexeme === undefined) {
421 | result += processBuffer();
422 | return 0;
423 | }
424 |
425 | var new_mode = subMode(lexeme, top);
426 | if (new_mode) {
427 | result += processBuffer();
428 | startNewMode(new_mode, lexeme);
429 | return new_mode.returnBegin ? 0 : lexeme.length;
430 | }
431 |
432 | var end_mode = endOfMode(top, lexeme);
433 | if (end_mode) {
434 | var origin = top;
435 | if (!(origin.returnEnd || origin.excludeEnd)) {
436 | mode_buffer += lexeme;
437 | }
438 | result += processBuffer();
439 | do {
440 | if (top.className) {
441 | result += '';
442 | }
443 | relevance += top.relevance;
444 | top = top.parent;
445 | } while (top != end_mode.parent);
446 | if (origin.excludeEnd) {
447 | result += escape(lexeme);
448 | }
449 | mode_buffer = '';
450 | if (end_mode.starts) {
451 | startNewMode(end_mode.starts, '');
452 | }
453 | return origin.returnEnd ? 0 : lexeme.length;
454 | }
455 |
456 | if (isIllegal(lexeme, top))
457 | throw new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.className || '..
blocks on a page.
647 | */
648 | function initHighlighting() {
649 | if (initHighlighting.called)
650 | return;
651 | initHighlighting.called = true;
652 |
653 | var blocks = document.querySelectorAll('pre code');
654 | Array.prototype.forEach.call(blocks, highlightBlock);
655 | }
656 |
657 | /*
658 | Attaches highlighting to the page load event.
659 | */
660 | function initHighlightingOnLoad() {
661 | addEventListener('DOMContentLoaded', initHighlighting, false);
662 | addEventListener('load', initHighlighting, false);
663 | }
664 |
665 | var languages = {};
666 | var aliases = {};
667 |
668 | function registerLanguage(name, language) {
669 | var lang = languages[name] = language(hljs);
670 | if (lang.aliases) {
671 | lang.aliases.forEach(function(alias) {aliases[alias] = name;});
672 | }
673 | }
674 |
675 | function listLanguages() {
676 | return Object.keys(languages);
677 | }
678 |
679 | function getLanguage(name) {
680 | return languages[name] || languages[aliases[name]];
681 | }
682 |
683 | /* Interface definition */
684 |
685 | hljs.highlight = highlight;
686 | hljs.highlightAuto = highlightAuto;
687 | hljs.fixMarkup = fixMarkup;
688 | hljs.highlightBlock = highlightBlock;
689 | hljs.configure = configure;
690 | hljs.initHighlighting = initHighlighting;
691 | hljs.initHighlightingOnLoad = initHighlightingOnLoad;
692 | hljs.registerLanguage = registerLanguage;
693 | hljs.listLanguages = listLanguages;
694 | hljs.getLanguage = getLanguage;
695 | hljs.inherit = inherit;
696 |
697 | // Common regexps
698 | hljs.IDENT_RE = '[a-zA-Z]\\w*';
699 | hljs.UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*';
700 | hljs.NUMBER_RE = '\\b\\d+(\\.\\d+)?';
701 | hljs.C_NUMBER_RE = '(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float
702 | hljs.BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b...
703 | hljs.RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~';
704 |
705 | // Common modes
706 | hljs.BACKSLASH_ESCAPE = {
707 | begin: '\\\\[\\s\\S]', relevance: 0
708 | };
709 | hljs.APOS_STRING_MODE = {
710 | className: 'string',
711 | begin: '\'', end: '\'',
712 | illegal: '\\n',
713 | contains: [hljs.BACKSLASH_ESCAPE]
714 | };
715 | hljs.QUOTE_STRING_MODE = {
716 | className: 'string',
717 | begin: '"', end: '"',
718 | illegal: '\\n',
719 | contains: [hljs.BACKSLASH_ESCAPE]
720 | };
721 | hljs.PHRASAL_WORDS_MODE = {
722 | begin: /\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/
723 | };
724 | hljs.COMMENT = function (begin, end, inherits) {
725 | var mode = hljs.inherit(
726 | {
727 | className: 'comment',
728 | begin: begin, end: end,
729 | contains: []
730 | },
731 | inherits || {}
732 | );
733 | mode.contains.push(hljs.PHRASAL_WORDS_MODE);
734 | mode.contains.push({
735 | className: 'doctag',
736 | begin: "(?:TODO|FIXME|NOTE|BUG|XXX):",
737 | relevance: 0
738 | });
739 | return mode;
740 | };
741 | hljs.C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$');
742 | hljs.C_BLOCK_COMMENT_MODE = hljs.COMMENT('/\\*', '\\*/');
743 | hljs.HASH_COMMENT_MODE = hljs.COMMENT('#', '$');
744 | hljs.NUMBER_MODE = {
745 | className: 'number',
746 | begin: hljs.NUMBER_RE,
747 | relevance: 0
748 | };
749 | hljs.C_NUMBER_MODE = {
750 | className: 'number',
751 | begin: hljs.C_NUMBER_RE,
752 | relevance: 0
753 | };
754 | hljs.BINARY_NUMBER_MODE = {
755 | className: 'number',
756 | begin: hljs.BINARY_NUMBER_RE,
757 | relevance: 0
758 | };
759 | hljs.CSS_NUMBER_MODE = {
760 | className: 'number',
761 | begin: hljs.NUMBER_RE + '(' +
762 | '%|em|ex|ch|rem' +
763 | '|vw|vh|vmin|vmax' +
764 | '|cm|mm|in|pt|pc|px' +
765 | '|deg|grad|rad|turn' +
766 | '|s|ms' +
767 | '|Hz|kHz' +
768 | '|dpi|dpcm|dppx' +
769 | ')?',
770 | relevance: 0
771 | };
772 | hljs.REGEXP_MODE = {
773 | className: 'regexp',
774 | begin: /\//, end: /\/[gimuy]*/,
775 | illegal: /\n/,
776 | contains: [
777 | hljs.BACKSLASH_ESCAPE,
778 | {
779 | begin: /\[/, end: /\]/,
780 | relevance: 0,
781 | contains: [hljs.BACKSLASH_ESCAPE]
782 | }
783 | ]
784 | };
785 | hljs.TITLE_MODE = {
786 | className: 'title',
787 | begin: hljs.IDENT_RE,
788 | relevance: 0
789 | };
790 | hljs.UNDERSCORE_TITLE_MODE = {
791 | className: 'title',
792 | begin: hljs.UNDERSCORE_IDENT_RE,
793 | relevance: 0
794 | };
795 |
796 | hljs.registerLanguage('solidity', function(hljs) {
797 | return {
798 | aliases: ['sol'],
799 | keywords: {
800 | keyword:
801 | 'in of if for while finally var new function do return void else break catch ' +
802 | 'instanceof with throw case default try this switch continue typeof delete ' +
803 | 'let yield const export super debugger as async await ' +
804 | 'mapping address struct internal public returns private ' +
805 | 'string uint uint8 uint16 uint32 uint64 uint128 ' +
806 | 'bytes4 bytes8 bytes16 bytes32 bytes64 bytes128 ' +
807 | 'now block timestamp coinbase difficulty gaslimit number blockhash gas msg.sender ' +
808 | 'gasprice origin contract this is modifier',
809 | literal:
810 | 'true false null undefined NaN Infinity',
811 | built_in:
812 | 'eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent ' +
813 | 'encodeURI encodeURIComponent escape unescape Object Function Boolean Error ' +
814 | 'EvalError InternalError RangeError ReferenceError StopIteration SyntaxError ' +
815 | 'TypeError URIError Number Math Date String RegExp Array Float32Array ' +
816 | 'Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array ' +
817 | 'Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require ' +
818 | 'module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect ' +
819 | 'Promise ' +
820 | 'sha3 sha256 ripemd160 ecrecover suicide call callcode '
821 | },
822 | contains: [
823 | {
824 | className: 'pi',
825 | relevance: 10,
826 | begin: /^\s*['"]use (strict|asm)['"]/
827 | },
828 | hljs.APOS_STRING_MODE,
829 | hljs.QUOTE_STRING_MODE,
830 | { // template string
831 | className: 'string',
832 | begin: '`', end: '`',
833 | contains: [
834 | hljs.BACKSLASH_ESCAPE,
835 | {
836 | className: 'subst',
837 | begin: '\\$\\{', end: '\\}'
838 | }
839 | ]
840 | },
841 | hljs.C_LINE_COMMENT_MODE,
842 | hljs.C_BLOCK_COMMENT_MODE,
843 | {
844 | className: 'number',
845 | variants: [
846 | { begin: '\\b(0[bB][01]+)' },
847 | { begin: '\\b(0[oO][0-7]+)' },
848 | { begin: hljs.C_NUMBER_RE }
849 | ],
850 | relevance: 0
851 | },
852 | { // "value" container
853 | begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*',
854 | keywords: 'return throw case',
855 | contains: [
856 | hljs.C_LINE_COMMENT_MODE,
857 | hljs.C_BLOCK_COMMENT_MODE,
858 | hljs.REGEXP_MODE,
859 | { // E4X / JSX
860 | begin: /, end: />\s*[);\]]/,
861 | relevance: 0,
862 | subLanguage: 'xml'
863 | }
864 | ],
865 | relevance: 0
866 | },
867 | {
868 | className: 'function',
869 | beginKeywords: 'function contract struct modifier', end: /\{/, excludeEnd: true,
870 | contains: [
871 | hljs.inherit(hljs.TITLE_MODE, {begin: /[A-Za-z$_][0-9A-Za-z$_]*/}),
872 | {
873 | className: 'params',
874 | begin: /\(/, end: /\)/,
875 | excludeBegin: true,
876 | excludeEnd: true,
877 | contains: [
878 | hljs.C_LINE_COMMENT_MODE,
879 | hljs.C_BLOCK_COMMENT_MODE
880 | ]
881 | }
882 | ],
883 | illegal: /\[|%/
884 | },
885 | {
886 | begin: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and `$.something`
887 | },
888 | {
889 | begin: '\\.' + hljs.IDENT_RE, relevance: 0 // hack: prevents detection of keywords after dots
890 | },
891 | // ECMAScript 6 modules import
892 | {
893 | beginKeywords: 'import', end: '[;$]',
894 | keywords: 'import from as',
895 | contains: [
896 | hljs.APOS_STRING_MODE,
897 | hljs.QUOTE_STRING_MODE
898 | ]
899 | },
900 | { // ES6 class
901 | className: 'class',
902 | beginKeywords: 'class', end: /[{;=]/, excludeEnd: true,
903 | illegal: /[:"\[\]]/,
904 | contains: [
905 | {beginKeywords: 'extends'},
906 | hljs.UNDERSCORE_TITLE_MODE
907 | ]
908 | }
909 | ],
910 | illegal: /#/
911 | };
912 | });
913 |
914 | return hljs;
915 | }));
916 |
--------------------------------------------------------------------------------