├── src
├── css
│ ├── css-editor-core.css
│ ├── jsonvue-error.css
│ ├── css-editor.css
│ ├── options.css
│ ├── jsonvue.css
│ └── jsonvue-core.css
├── resources
│ ├── jsonvue16.png
│ ├── jsonvue48.png
│ └── jsonvue128.png
├── manifest.json
├── css-editor.html
├── codemirror
│ ├── LICENSE
│ ├── codemirror.css
│ └── css.js
├── options.html
└── js
│ ├── pages
│ ├── options.js
│ └── css-editor.js
│ ├── background.js
│ ├── workers
│ ├── formatter.js
│ ├── linter.js
│ └── parser.js
│ └── content.js
├── README.md
├── .eslintrc.js
└── LICENSE.txt
/src/css/css-editor-core.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: initial;
3 | font-size: initial;
4 | }
--------------------------------------------------------------------------------
/src/resources/jsonvue16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gildas-lormeau/JSONVue/HEAD/src/resources/jsonvue16.png
--------------------------------------------------------------------------------
/src/resources/jsonvue48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gildas-lormeau/JSONVue/HEAD/src/resources/jsonvue48.png
--------------------------------------------------------------------------------
/src/resources/jsonvue128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gildas-lormeau/JSONVue/HEAD/src/resources/jsonvue128.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JSONVue
2 | Fork of JSONView for Chromium-based browsers
3 |
4 | This is the source code of JSONVue on Chrome, see https://chrome.google.com/webstore/detail/jsonvue/chklaanhfefbnpoihckbnefhakgolnmc
5 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /* global module */
2 |
3 | module.exports = {
4 | "env": {
5 | "es6": true,
6 | "node": false,
7 | "browser": false
8 | },
9 | "globals": {
10 | "console": true
11 | },
12 | "extends": "eslint:recommended",
13 | "parserOptions": {
14 | "ecmaVersion": 2017,
15 | "sourceType": "module"
16 | },
17 | "ignorePatterns": [
18 | "dist/"
19 | ],
20 | "rules": {
21 | "indent": [
22 | "error",
23 | "tab", {
24 | "SwitchCase": 1
25 | }
26 | ],
27 | "linebreak-style": [
28 | "error",
29 | "unix"
30 | ],
31 | "quotes": [
32 | "error",
33 | "double"
34 | ],
35 | "semi": [
36 | "error",
37 | "always"
38 | ],
39 | "no-console": [
40 | "warn"
41 | ]
42 | }
43 | };
--------------------------------------------------------------------------------
/src/css/jsonvue-error.css:
--------------------------------------------------------------------------------
1 | .error-position {
2 | display: inline-block;
3 | vertical-align: middle;
4 | }
5 |
6 | .error-position .error-icon {
7 | color: fireBrick;
8 | width: 21px;
9 | display: inline-block;
10 | text-align: center;
11 | }
12 |
13 | .container {
14 | position: absolute;
15 | left: 0px;
16 | width: 100%;
17 | }
18 |
19 | .content {
20 | top: 3px;
21 | width: 30em;
22 | margin: 0 auto;
23 | background-color: #FEE;
24 | border: 2px solid #933;
25 | color: #933;
26 | padding: 20px;
27 | position: relative;
28 | box-shadow: #888 3px 3px 5px;
29 | }
30 |
31 | .close-error::after {
32 | content: "✖";
33 | width: 16px;
34 | position: absolute;
35 | top: 3px;
36 | right: 3px;
37 | cursor: pointer;
38 | }
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "JSONVue",
3 | "icons": {
4 | "16": "resources/jsonvue16.png",
5 | "48": "resources/jsonvue48.png",
6 | "128": "resources/jsonvue128.png"
7 | },
8 | "version": "0.2.3",
9 | "description": "Validate and view JSON documents",
10 | "options_ui": {
11 | "browser_style": true,
12 | "page": "options.html",
13 | "open_in_tab": false
14 | },
15 | "background": {
16 | "service_worker": "js/background.js"
17 | },
18 | "content_scripts": [
19 | {
20 | "matches": [
21 | "http://*/*",
22 | "https://*/*",
23 | "ftp://*/*",
24 | "file:///*"
25 | ],
26 | "js": [
27 | "js/content.js"
28 | ],
29 | "run_at": "document_end",
30 | "all_frames": true
31 | }
32 | ],
33 | "permissions": [
34 | "contextMenus",
35 | "storage"
36 | ],
37 | "manifest_version": 3
38 | }
--------------------------------------------------------------------------------
/src/css-editor.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Style editor - JSONVue
7 |
8 |
9 |
10 |
11 |
12 |
13 |
20 |
21 |
22 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/codemirror/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (C) 2017 by Marijn Haverbeke and others
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Original work Copyright (c) 2009 Benjamin Hollis
4 | Modified work Copyright (c) 2012 Gildas Lormeau
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
--------------------------------------------------------------------------------
/src/css/css-editor.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: 10pt;
3 | font-family: sans-serif;
4 | }
5 |
6 | .container {
7 | margin-left: auto;
8 | margin-right: auto;
9 | padding-left: 10px;
10 | padding-right: 10px;
11 | max-width: 1200px;
12 | }
13 |
14 | header {
15 | display: flex;
16 | align-items: center;
17 | }
18 |
19 | h2 {
20 | flex: 1;
21 | }
22 |
23 | main {
24 | display: flex;
25 | }
26 |
27 | .panel {
28 | display: flex;
29 | flex-direction: column;
30 | width: 50%;
31 | margin: 5px;
32 | }
33 |
34 | .panel-label {
35 | padding-left: 2px;
36 | padding-bottom: 5px;
37 | }
38 |
39 | #previewer, .CodeMirror {
40 | background-color: white;
41 | border-width: 1px;
42 | border-style: solid;
43 | border-color: #aaa;
44 | height: 500px;
45 | }
46 |
47 | @media (orientation: portrait) {
48 | main {
49 | flex-direction: column;
50 | }
51 |
52 | .panel {
53 | width: 100%;
54 | }
55 |
56 | #previewer, .CodeMirror {
57 | height: 40vh;
58 | }
59 |
60 | #previewer {
61 | max-height: 300px;
62 | }
63 | }
64 |
65 | @media (prefers-color-scheme: dark) {
66 | body {
67 | background-color: #282828;
68 | color: lightgrey;
69 | }
70 |
71 | .CodeMirror {
72 | filter: invert(1);
73 | background-color: #d7d7d7;
74 | }
75 | }
--------------------------------------------------------------------------------
/src/css/options.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: 13px;
3 | }
4 |
5 | form {
6 | margin-top: 0px;
7 | margin-left: auto;
8 | margin-right: auto;
9 | }
10 |
11 | fieldset {
12 | border-width: 0px;
13 | }
14 |
15 | section {
16 | display: flex;
17 | align-items: end;
18 | }
19 |
20 | section.vertical {
21 | align-items: flex-start;
22 | flex-direction: column;
23 | }
24 |
25 | section:last-child {
26 | flex-direction: column;
27 | margin-top: 20px;
28 | }
29 |
30 | section label {
31 | flex-grow: 1;
32 | user-select: none;
33 | margin-bottom: 5px;
34 | }
35 |
36 | section:not(:first-child) label {
37 | margin-top: 10px;
38 | }
39 |
40 | input {
41 | margin-bottom: 5px;
42 | }
43 |
44 | legend {
45 | font-size: 15px;
46 | font-weight: 700;
47 | padding-left: 10px;
48 | padding-right: 10px;
49 | margin-bottom: 5px;
50 | }
51 |
52 | input[type=checkbox] {
53 | margin-right: 0px;
54 | }
55 |
56 | input[type=number] {
57 | width: 35px;
58 | text-align: right;
59 | }
60 |
61 | input[type=text] {
62 | width: 100%;
63 | width: calc(100% - 8px);
64 | }
65 |
66 | button {
67 | max-height: 21px;
68 | }
69 |
70 | .icon {
71 | width: 20px;
72 | padding-right: 5px;
73 | vertical-align: bottom;
74 | }
75 |
76 | @media (prefers-color-scheme: dark) {
77 | body {
78 | background-color: #292a2d;
79 | color: lightgrey;
80 | }
81 | }
--------------------------------------------------------------------------------
/src/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | JSONVue options
7 |
8 |
9 |
10 |
11 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/css/jsonvue.css:
--------------------------------------------------------------------------------
1 | body {
2 | white-space: pre-wrap;
3 | word-break: break-word;
4 | font-family: monospace;
5 | }
6 |
7 | .property {
8 | font-weight: bold;
9 | }
10 |
11 | .type-null {
12 | color: gray;
13 | }
14 |
15 | .type-boolean {
16 | color: firebrick;
17 | }
18 |
19 | .type-number {
20 | color: blue;
21 | }
22 |
23 | .type-string {
24 | color: green;
25 | }
26 |
27 | .callback-function {
28 | color: gray;
29 | }
30 |
31 | .ellipsis::after {
32 | content: " … ";
33 | }
34 |
35 | .collapser {
36 | position: absolute;
37 | top: .1em;
38 | left: -2ch;
39 | cursor: default;
40 | user-select: none;
41 | padding-inline: 0.5ch;
42 | }
43 |
44 | .collapser::after {
45 | cursor: pointer;
46 | content: "-";
47 | }
48 |
49 | .collapsed > .collapser::after {
50 | content: "+";
51 | }
52 |
53 | .collapsible {
54 | margin-inline-start: 4ch;
55 | }
56 |
57 | .collapsible .collapsible::before {
58 | content: "";
59 | position: absolute;
60 | left: 0.5ch;
61 | top: 1.8em;
62 | height: calc(100% - 3.6em);
63 | border: 0;
64 | border-inline-start: #d3d3d3 0.2ch dashed;
65 | }
66 |
67 | .hoverable {
68 | display: inline-block;
69 | padding: 0.1em;
70 | transition: background-color 0.2s ease-out 0s;
71 | }
72 |
73 | .hovered {
74 | background-color: rgba(235, 238, 249, 1);
75 | transition-delay: 0.2s;
76 | }
77 |
78 | .selected {
79 | outline: dotted 0.1ch;
80 | }
81 |
82 | @media (prefers-color-scheme: dark) {
83 | body {
84 | background-color: #282828;
85 | color: lightgrey;
86 | }
87 |
88 | .hovered {
89 | background-color: #424242;
90 | }
91 |
92 | .type-boolean {
93 | color: tomato;
94 | }
95 |
96 | .type-number {
97 | color: dodgerblue;
98 | }
99 |
100 | .type-string {
101 | color: yellowgreen;
102 | }
103 |
104 | a {
105 | color: dodgerblue;
106 | }
107 |
108 | .collapsible .collapsible::before {
109 | border-color: #484848;
110 | }
111 | }
--------------------------------------------------------------------------------
/src/js/pages/options.js:
--------------------------------------------------------------------------------
1 | /* global document, chrome, open */
2 |
3 | const injectInFrameInput = document.getElementById("injectInFrameInput");
4 | const supportBigIntInput = document.getElementById("supportBigIntInput");
5 | const addContextMenuInput = document.getElementById("addContextMenuInput");
6 | const maxDepthLevelExpandedInput = document.getElementById("maxDepthLevelExpandedInput");
7 | const jsonPrefixInput = document.getElementById("jsonPrefixInput");
8 | document.getElementById("openEditorButton").addEventListener("click", event => {
9 | open("css-editor.html", "jsonvue-css-editor");
10 | event.stopPropagation();
11 | }, false);
12 | document.getElementById("resetButton").addEventListener("click", event => {
13 | chrome.runtime.sendMessage({ resetOptions: true }, init);
14 | event.stopPropagation();
15 | }, false);
16 | init();
17 |
18 | function init() {
19 | chrome.runtime.sendMessage({ getOptions: true }, options => {
20 | injectInFrameInput.checked = options.injectInFrame;
21 | supportBigIntInput.checked = options.supportBigInt;
22 | addContextMenuInput.checked = options.addContextMenu;
23 | maxDepthLevelExpandedInput.valueAsNumber = options.maxDepthLevelExpanded;
24 | jsonPrefixInput.value = options.jsonPrefix;
25 | injectInFrameInput.onchange = () => {
26 | options.injectInFrame = injectInFrameInput.checked;
27 | chrome.runtime.sendMessage({ setSetting: true, name: "options", value: options });
28 | };
29 | supportBigIntInput.onchange = () => {
30 | options.supportBigInt = supportBigIntInput.checked;
31 | chrome.runtime.sendMessage({ setSetting: true, name: "options", value: options });
32 | };
33 | addContextMenuInput.onchange = () => {
34 | options.addContextMenu = addContextMenuInput.checked;
35 | chrome.runtime.sendMessage({ setSetting: true, refreshMenuEntry: true, name: "options", value: options });
36 | };
37 | maxDepthLevelExpandedInput.onchange = () => {
38 | options.maxDepthLevelExpanded = maxDepthLevelExpandedInput.valueAsNumber;
39 | chrome.runtime.sendMessage({ setSetting: true, name: "options", value: options });
40 | };
41 | jsonPrefixInput.onchange = () => {
42 | options.jsonPrefix = jsonPrefixInput.value;
43 | chrome.runtime.sendMessage({ setSetting: true, name: "options", value: options });
44 | };
45 | });
46 | }
--------------------------------------------------------------------------------
/src/css/jsonvue-core.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin-bottom: 23px;
3 | }
4 |
5 | ul {
6 | list-style-type: none;
7 | padding: 0;
8 | margin: 0 0 0 2em;
9 | }
10 |
11 | li {
12 | position: relative;
13 | }
14 |
15 | .hoverable {
16 | display: inline-block;
17 | }
18 |
19 | .collapsed>.collapsible {
20 | display: none;
21 | }
22 |
23 | .ellipsis {
24 | display: none;
25 | }
26 |
27 | .collapsed>.ellipsis {
28 | display: inherit;
29 | }
30 |
31 | .collapser {
32 | position: absolute;
33 | top: .1em;
34 | left: -1.4em;
35 | cursor: default;
36 | }
37 |
38 | .collapser::after {
39 | cursor: pointer;
40 | }
41 |
42 | .collapsible .collapsible::before {
43 | top: 1.8em;
44 | }
45 |
46 | .status {
47 | position: fixed;
48 | left: 0;
49 | bottom: 0;
50 | border-color: #c2c2c2;
51 | border-top-width: 1px;
52 | border-right-width: 1px;
53 | border-bottom-width: 0px;
54 | border-left-width: 0px;
55 | border-style: solid;
56 | border-top-right-radius: 4px;
57 | height: 16px;
58 | padding-top: 2px;
59 | padding-bottom: 2px;
60 | padding-right: 7px;
61 | padding-left: 4px;
62 | font-family: sans-serif;
63 | font-size: 12px;
64 | opacity: 0;
65 | background-color: #d2d2f6;
66 | color: #696969;
67 | transition: opacity .2s ease-out;
68 | user-select: none;
69 | }
70 |
71 | .status:not(:empty) {
72 | opacity: 1;
73 | }
74 |
75 | .toolbox {
76 | padding-right: 3px;
77 | font-family: sans-serif;
78 | font-size: 15px;
79 | opacity: .25;
80 | background-color: #d2d2f6;
81 | position: fixed;
82 | right: 0px;
83 | top: 0px;
84 | border-color: #c2c2c2;
85 | border-bottom-width: 1px;
86 | border-left-width: 1px;
87 | border-top-width: 0px;
88 | border-right-width: 0px;
89 | border-style: solid;
90 | border-bottom-left-radius: 4px;
91 | padding-bottom: 3px;
92 | transition: opacity .2s ease-out;
93 | cursor: default;
94 | user-select: none;
95 | padding-left: 2px;
96 | }
97 |
98 | .toolbox:hover {
99 | opacity: 1;
100 | }
101 |
102 | .toolbox>* {
103 | display: inline-block;
104 | padding-left: 3px;
105 | padding-right: 3px;
106 | cursor: pointer;
107 | min-width: 14px;
108 | text-align: center;
109 | }
110 |
111 | .toolbox>a {
112 | font-size: 13px;
113 | }
114 |
115 | @media (prefers-color-scheme: dark) {
116 | .toolbox {
117 | background-color: #484848;
118 | border-color: #242424;
119 | }
120 |
121 | .status {
122 | background-color: #484848;
123 | border-color: #242424;
124 | color: lightgrey;
125 | }
126 | }
--------------------------------------------------------------------------------
/src/js/pages/css-editor.js:
--------------------------------------------------------------------------------
1 | /* global document, chrome, fetch, setTimeout, clearTimeout, CodeMirror */
2 |
3 | const SAMPLE_PART1 = "";
5 | const PASSIVE_KEYS = ["ArrowDown", "ArrowUp", "ArrowLeft", "ArrowRight", "End", "Home", "PageDown", "PageUp", "ControlLeft", "ControlRight", "AltLeft", "ShiftLeft", "ShiftRight", "Insert"];
6 |
7 | const editor = document.getElementById("editor");
8 | const resetButton = document.getElementById("reset-button");
9 | const saveButton = document.getElementById("save-button");
10 | const previewer = document.getElementById("previewer").contentWindow;
11 |
12 | let timeoutOnKey;
13 | const codemirror = CodeMirror.fromTextArea(editor);
14 | codemirror.on("keyup", onKeyUpEditor);
15 | resetButton.addEventListener("click", resetTheme, false);
16 | saveButton.addEventListener("click", () => chrome.runtime.sendMessage({ setSetting: true, name: "theme", value: codemirror.getValue() }), false);
17 | chrome.runtime.sendMessage({ getTheme: true }, init);
18 |
19 | function init(theme) {
20 | codemirror.setValue(theme);
21 | updatePreview();
22 | }
23 |
24 | async function resetTheme() {
25 | codemirror.setValue(await (await fetch("css/jsonvue.css")).text());
26 | updatePreview();
27 | }
28 |
29 | function onKeyUpEditor(editor, event) {
30 | if (PASSIVE_KEYS.indexOf(event.code) == -1) {
31 | if (timeoutOnKey) {
32 | clearTimeout(timeoutOnKey);
33 | }
34 | timeoutOnKey = setTimeout(updatePreview, 500);
35 | }
36 | }
37 |
38 | function updatePreview() {
39 | previewer.document.open();
40 | previewer.document.write(SAMPLE_PART1);
41 | previewer.document.write(codemirror.getValue());
42 | previewer.document.write(SAMPLE_PART2);
43 | previewer.document.close();
44 | }
--------------------------------------------------------------------------------
/src/js/background.js:
--------------------------------------------------------------------------------
1 | /* global chrome, fetch, Worker, localStorage, importScripts, formatter, linter, TextEncoder, crypto */
2 |
3 | const WORKER_API_AVAILABLE = typeof Worker != "undefined";
4 | const LOCAL_STORAGE_API_AVAILABLE = typeof localStorage != "undefined";
5 | const MENU_ID_COPY_PATH = "copy-path";
6 | const MENU_ID_COPY_VALUE = "copy-value";
7 | const MENU_ID_COPY_JSON_VALUE = "copy-json-value";
8 | const DEFAULT_OPTIONS = {
9 | maxDepthLevelExpanded: 0,
10 | addContextMenu: true,
11 | jsonPrefix: "^\\)]}',|for\\s*\\(;;\\);|while\\s*(1);"
12 | };
13 | const LEGACY_STYLESHEET_HASH = "[217,103,31,97,255,43,250,60,65,196,134,101,148,173,69,129,51,72,223,43]";
14 |
15 | if (!WORKER_API_AVAILABLE) {
16 | importScripts("/js/workers/formatter.js");
17 | importScripts("/js/workers/linter.js");
18 | }
19 |
20 | let extensionReady;
21 | chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
22 | onMessage(message).then(sendResponse);
23 | return true;
24 | });
25 | chrome.contextMenus.onClicked.addListener((info, tab) => chrome.tabs.sendMessage(tab.id, {
26 | copy: true,
27 | type: info.menuItemId
28 | }));
29 | addMenuEntry(true);
30 | init();
31 |
32 | async function init() {
33 | extensionReady = migrateSettings();
34 | await initDefaultSettings(await getSettings());
35 | await refreshMenuEntry();
36 | }
37 |
38 | async function migrateSettings() {
39 | const promises = [];
40 | if (LOCAL_STORAGE_API_AVAILABLE) {
41 | if (localStorage.options) {
42 | promises.push(new Promise(resolve => {
43 | chrome.storage.local.set({ options: JSON.parse(localStorage.options) }, () => resolve());
44 | delete localStorage.options;
45 | }));
46 | }
47 | if (localStorage.theme) {
48 | promises.push(new Promise(resolve => {
49 | chrome.storage.local.set({ theme: localStorage.theme }, () => resolve());
50 | delete localStorage.theme;
51 | }));
52 | }
53 | }
54 | await Promise.all(promises);
55 | }
56 |
57 | async function initDefaultSettings(settings) {
58 | let optionsChanged;
59 | if (!settings.options) {
60 | settings.options = {};
61 | optionsChanged = true;
62 | }
63 | const options = settings.options;
64 | if (typeof options.maxDepthLevelExpanded == "undefined") {
65 | options.maxDepthLevelExpanded = DEFAULT_OPTIONS.maxDepthLevelExpanded;
66 | optionsChanged = true;
67 | }
68 | if (typeof options.addContextMenu == "undefined") {
69 | options.addContextMenu = DEFAULT_OPTIONS.addContextMenu;
70 | optionsChanged = true;
71 | }
72 | if (typeof options.jsonPrefix == "undefined") {
73 | options.jsonPrefix = DEFAULT_OPTIONS.jsonPrefix;
74 | optionsChanged = true;
75 | }
76 | if (optionsChanged) {
77 | await setSetting("options", options);
78 | }
79 | if (settings.theme) {
80 | const encoder = new TextEncoder();
81 | const hash = JSON.stringify(Array.from(new Uint8Array(await crypto.subtle.digest("SHA-1", encoder.encode(settings.theme)))));
82 | if (hash == LEGACY_STYLESHEET_HASH) {
83 | await setSetting("theme", await getDefaultTheme());
84 | }
85 | } else {
86 | await setSetting("theme", await getDefaultTheme());
87 | }
88 | }
89 |
90 | async function onMessage(message) {
91 | let result;
92 | if (message.getTheme) {
93 | result = (await getSettings()).theme;
94 | }
95 | if (message.getOptions) {
96 | result = (await getSettings()).options;
97 | }
98 | if (message.setSetting) {
99 | await setSetting(message.name, message.value);
100 | }
101 | if (message.jsonToHTML) {
102 | result = formatHTML(message.json, message.functionName, message.supportBigInt);
103 | }
104 | if (message.resetOptions) {
105 | await setSetting("options", DEFAULT_OPTIONS);
106 | }
107 | if (message.refreshMenuEntry) {
108 | await refreshMenuEntry();
109 | }
110 | return result || {};
111 | }
112 |
113 | async function formatHTML(json, functionName, supportBigInt) {
114 | const result = await Promise.all([formatHTMLAsync(json, functionName, supportBigInt), getContentStylesheet()]);
115 | result[0].stylesheet = result[1];
116 | return result[0];
117 | }
118 |
119 | async function formatHTMLAsync(json, functionName, supportBigInt) {
120 | if (WORKER_API_AVAILABLE) {
121 | const response = await executeWorker("js/workers/formatter.js", { json: json, functionName, supportBigInt });
122 | if (response.html) {
123 | return { html: response.html };
124 | }
125 | if (response.error) {
126 | const response = await executeWorker("js/workers/linter.js", json);
127 | return { error: response.error, loc: response.loc };
128 | }
129 | } else {
130 | try {
131 | return { html: formatter.format(json, functionName, supportBigInt) };
132 | } catch (error) {
133 | const response = linter.lint(json);
134 | return { error: response.error, loc: response.loc };
135 | }
136 | }
137 | }
138 |
139 | function executeWorker(path, message) {
140 | return new Promise((resolve, reject) => {
141 | const worker = new Worker(path);
142 | worker.addEventListener("message", onMessage, false);
143 | worker.addEventListener("error", onError, false);
144 | worker.postMessage(message);
145 |
146 | function onMessage(event) {
147 | worker.removeEventListener("message", onMessage, false);
148 | worker.removeEventListener("error", onError, false);
149 | worker.terminate();
150 | resolve(event.data);
151 | }
152 |
153 | function onError(event) {
154 | reject(event.detail.error);
155 | }
156 | });
157 | }
158 |
159 | async function refreshMenuEntry() {
160 | const settings = await getSettings();
161 | chrome.contextMenus.removeAll();
162 | if (settings.options.addContextMenu) {
163 | addMenuEntry();
164 | }
165 | }
166 |
167 | function addMenuEntry(removeAll) {
168 | if (removeAll) {
169 | chrome.contextMenus.removeAll();
170 | }
171 | chrome.contextMenus.create({
172 | id: MENU_ID_COPY_PATH,
173 | title: "Copy path",
174 | contexts: ["page", "selection", "link"]
175 | });
176 | chrome.contextMenus.create({
177 | id: MENU_ID_COPY_VALUE,
178 | title: "Copy value",
179 | contexts: ["page", "selection", "link"]
180 | });
181 | chrome.contextMenus.create({
182 | id: MENU_ID_COPY_JSON_VALUE,
183 | title: "Copy JSON value",
184 | contexts: ["page", "selection", "link"]
185 | });
186 | }
187 |
188 | async function getDefaultTheme() {
189 | return (await fetch("/css/jsonvue.css")).text();
190 | }
191 |
192 | async function getContentStylesheet() {
193 | return (await Promise.all([
194 | (await fetch("/css/jsonvue-error.css")).text(),
195 | (await fetch("/css/jsonvue-core.css")).text(),
196 | (await getSettings()).theme
197 | ])).join("\n");
198 | }
199 |
200 | async function getSettings() {
201 | await extensionReady;
202 | return new Promise(resolve => chrome.storage.local.get(["options", "theme"], result => resolve(result)));
203 | }
204 |
205 | async function setSetting(name, value) {
206 | await extensionReady;
207 | return new Promise(resolve => chrome.storage.local.set({ [name]: value }, result => resolve(result)));
208 | }
--------------------------------------------------------------------------------
/src/codemirror/codemirror.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 |
3 | .CodeMirror {
4 | /* Set height, width, borders, and global font properties here */
5 | font-family: monospace;
6 | height: 300px;
7 | color: black;
8 | direction: ltr;
9 | }
10 |
11 | /* PADDING */
12 |
13 | .CodeMirror-lines {
14 | padding: 4px 0; /* Vertical padding around content */
15 | }
16 | .CodeMirror pre.CodeMirror-line,
17 | .CodeMirror pre.CodeMirror-line-like {
18 | padding: 0 4px; /* Horizontal padding of content */
19 | }
20 |
21 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
22 | background-color: white; /* The little square between H and V scrollbars */
23 | }
24 |
25 | /* GUTTER */
26 |
27 | .CodeMirror-gutters {
28 | border-right: 1px solid #ddd;
29 | background-color: #f7f7f7;
30 | white-space: nowrap;
31 | }
32 | .CodeMirror-linenumbers {}
33 | .CodeMirror-linenumber {
34 | padding: 0 3px 0 5px;
35 | min-width: 20px;
36 | text-align: right;
37 | color: #999;
38 | white-space: nowrap;
39 | }
40 |
41 | .CodeMirror-guttermarker { color: black; }
42 | .CodeMirror-guttermarker-subtle { color: #999; }
43 |
44 | /* CURSOR */
45 |
46 | .CodeMirror-cursor {
47 | border-left: 1px solid black;
48 | border-right: none;
49 | width: 0;
50 | }
51 | /* Shown when moving in bi-directional text */
52 | .CodeMirror div.CodeMirror-secondarycursor {
53 | border-left: 1px solid silver;
54 | }
55 | .cm-fat-cursor .CodeMirror-cursor {
56 | width: auto;
57 | border: 0 !important;
58 | background: #7e7;
59 | }
60 | .cm-fat-cursor div.CodeMirror-cursors {
61 | z-index: 1;
62 | }
63 | .cm-fat-cursor .CodeMirror-line::selection,
64 | .cm-fat-cursor .CodeMirror-line > span::selection,
65 | .cm-fat-cursor .CodeMirror-line > span > span::selection { background: transparent; }
66 | .cm-fat-cursor .CodeMirror-line::-moz-selection,
67 | .cm-fat-cursor .CodeMirror-line > span::-moz-selection,
68 | .cm-fat-cursor .CodeMirror-line > span > span::-moz-selection { background: transparent; }
69 | .cm-fat-cursor { caret-color: transparent; }
70 | @-moz-keyframes blink {
71 | 0% {}
72 | 50% { background-color: transparent; }
73 | 100% {}
74 | }
75 | @-webkit-keyframes blink {
76 | 0% {}
77 | 50% { background-color: transparent; }
78 | 100% {}
79 | }
80 | @keyframes blink {
81 | 0% {}
82 | 50% { background-color: transparent; }
83 | 100% {}
84 | }
85 |
86 | /* Can style cursor different in overwrite (non-insert) mode */
87 | .CodeMirror-overwrite .CodeMirror-cursor {}
88 |
89 | .cm-tab { display: inline-block; text-decoration: inherit; }
90 |
91 | .CodeMirror-rulers {
92 | position: absolute;
93 | left: 0; right: 0; top: -50px; bottom: 0;
94 | overflow: hidden;
95 | }
96 | .CodeMirror-ruler {
97 | border-left: 1px solid #ccc;
98 | top: 0; bottom: 0;
99 | position: absolute;
100 | }
101 |
102 | /* DEFAULT THEME */
103 |
104 | .cm-s-default .cm-header {color: blue;}
105 | .cm-s-default .cm-quote {color: #090;}
106 | .cm-negative {color: #d44;}
107 | .cm-positive {color: #292;}
108 | .cm-header, .cm-strong {font-weight: bold;}
109 | .cm-em {font-style: italic;}
110 | .cm-link {text-decoration: underline;}
111 | .cm-strikethrough {text-decoration: line-through;}
112 |
113 | .cm-s-default .cm-keyword {color: #708;}
114 | .cm-s-default .cm-atom {color: #219;}
115 | .cm-s-default .cm-number {color: #164;}
116 | .cm-s-default .cm-def {color: #00f;}
117 | .cm-s-default .cm-variable,
118 | .cm-s-default .cm-punctuation,
119 | .cm-s-default .cm-property,
120 | .cm-s-default .cm-operator {}
121 | .cm-s-default .cm-variable-2 {color: #05a;}
122 | .cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
123 | .cm-s-default .cm-comment {color: #a50;}
124 | .cm-s-default .cm-string {color: #a11;}
125 | .cm-s-default .cm-string-2 {color: #f50;}
126 | .cm-s-default .cm-meta {color: #555;}
127 | .cm-s-default .cm-qualifier {color: #555;}
128 | .cm-s-default .cm-builtin {color: #30a;}
129 | .cm-s-default .cm-bracket {color: #997;}
130 | .cm-s-default .cm-tag {color: #170;}
131 | .cm-s-default .cm-attribute {color: #00c;}
132 | .cm-s-default .cm-hr {color: #999;}
133 | .cm-s-default .cm-link {color: #00c;}
134 |
135 | .cm-s-default .cm-error {color: #f00;}
136 | .cm-invalidchar {color: #f00;}
137 |
138 | .CodeMirror-composing { border-bottom: 2px solid; }
139 |
140 | /* Default styles for common addons */
141 |
142 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
143 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
144 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
145 | .CodeMirror-activeline-background {background: #e8f2ff;}
146 |
147 | /* STOP */
148 |
149 | /* The rest of this file contains styles related to the mechanics of
150 | the editor. You probably shouldn't touch them. */
151 |
152 | .CodeMirror {
153 | position: relative;
154 | overflow: hidden;
155 | background: white;
156 | }
157 |
158 | .CodeMirror-scroll {
159 | overflow: scroll !important; /* Things will break if this is overridden */
160 | /* 50px is the magic margin used to hide the element's real scrollbars */
161 | /* See overflow: hidden in .CodeMirror */
162 | margin-bottom: -50px; margin-right: -50px;
163 | padding-bottom: 50px;
164 | height: 100%;
165 | outline: none; /* Prevent dragging from highlighting the element */
166 | position: relative;
167 | }
168 | .CodeMirror-sizer {
169 | position: relative;
170 | border-right: 50px solid transparent;
171 | }
172 |
173 | /* The fake, visible scrollbars. Used to force redraw during scrolling
174 | before actual scrolling happens, thus preventing shaking and
175 | flickering artifacts. */
176 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
177 | position: absolute;
178 | z-index: 6;
179 | display: none;
180 | outline: none;
181 | }
182 | .CodeMirror-vscrollbar {
183 | right: 0; top: 0;
184 | overflow-x: hidden;
185 | overflow-y: scroll;
186 | }
187 | .CodeMirror-hscrollbar {
188 | bottom: 0; left: 0;
189 | overflow-y: hidden;
190 | overflow-x: scroll;
191 | }
192 | .CodeMirror-scrollbar-filler {
193 | right: 0; bottom: 0;
194 | }
195 | .CodeMirror-gutter-filler {
196 | left: 0; bottom: 0;
197 | }
198 |
199 | .CodeMirror-gutters {
200 | position: absolute; left: 0; top: 0;
201 | min-height: 100%;
202 | z-index: 3;
203 | }
204 | .CodeMirror-gutter {
205 | white-space: normal;
206 | height: 100%;
207 | display: inline-block;
208 | vertical-align: top;
209 | margin-bottom: -50px;
210 | }
211 | .CodeMirror-gutter-wrapper {
212 | position: absolute;
213 | z-index: 4;
214 | background: none !important;
215 | border: none !important;
216 | }
217 | .CodeMirror-gutter-background {
218 | position: absolute;
219 | top: 0; bottom: 0;
220 | z-index: 4;
221 | }
222 | .CodeMirror-gutter-elt {
223 | position: absolute;
224 | cursor: default;
225 | z-index: 4;
226 | }
227 | .CodeMirror-gutter-wrapper ::selection { background-color: transparent }
228 | .CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
229 |
230 | .CodeMirror-lines {
231 | cursor: text;
232 | min-height: 1px; /* prevents collapsing before first draw */
233 | }
234 | .CodeMirror pre.CodeMirror-line,
235 | .CodeMirror pre.CodeMirror-line-like {
236 | /* Reset some styles that the rest of the page might have set */
237 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
238 | border-width: 0;
239 | background: transparent;
240 | font-family: inherit;
241 | font-size: inherit;
242 | margin: 0;
243 | white-space: pre;
244 | word-wrap: normal;
245 | line-height: inherit;
246 | color: inherit;
247 | z-index: 2;
248 | position: relative;
249 | overflow: visible;
250 | -webkit-tap-highlight-color: transparent;
251 | -webkit-font-variant-ligatures: contextual;
252 | font-variant-ligatures: contextual;
253 | }
254 | .CodeMirror-wrap pre.CodeMirror-line,
255 | .CodeMirror-wrap pre.CodeMirror-line-like {
256 | word-wrap: break-word;
257 | white-space: pre-wrap;
258 | word-break: normal;
259 | }
260 |
261 | .CodeMirror-linebackground {
262 | position: absolute;
263 | left: 0; right: 0; top: 0; bottom: 0;
264 | z-index: 0;
265 | }
266 |
267 | .CodeMirror-linewidget {
268 | position: relative;
269 | z-index: 2;
270 | padding: 0.1px; /* Force widget margins to stay inside of the container */
271 | }
272 |
273 | .CodeMirror-widget {}
274 |
275 | .CodeMirror-rtl pre { direction: rtl; }
276 |
277 | .CodeMirror-code {
278 | outline: none;
279 | }
280 |
281 | /* Force content-box sizing for the elements where we expect it */
282 | .CodeMirror-scroll,
283 | .CodeMirror-sizer,
284 | .CodeMirror-gutter,
285 | .CodeMirror-gutters,
286 | .CodeMirror-linenumber {
287 | -moz-box-sizing: content-box;
288 | box-sizing: content-box;
289 | }
290 |
291 | .CodeMirror-measure {
292 | position: absolute;
293 | width: 100%;
294 | height: 0;
295 | overflow: hidden;
296 | visibility: hidden;
297 | }
298 |
299 | .CodeMirror-cursor {
300 | position: absolute;
301 | pointer-events: none;
302 | }
303 | .CodeMirror-measure pre { position: static; }
304 |
305 | div.CodeMirror-cursors {
306 | visibility: hidden;
307 | position: relative;
308 | z-index: 3;
309 | }
310 | div.CodeMirror-dragcursors {
311 | visibility: visible;
312 | }
313 |
314 | .CodeMirror-focused div.CodeMirror-cursors {
315 | visibility: visible;
316 | }
317 |
318 | .CodeMirror-selected { background: #d9d9d9; }
319 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
320 | .CodeMirror-crosshair { cursor: crosshair; }
321 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
322 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
323 |
324 | .cm-searching {
325 | background-color: #ffa;
326 | background-color: rgba(255, 255, 0, .4);
327 | }
328 |
329 | /* Used to force a border model for a node */
330 | .cm-force-border { padding-right: .1px; }
331 |
332 | @media print {
333 | /* Hide the cursor when printing */
334 | .CodeMirror div.CodeMirror-cursors {
335 | visibility: hidden;
336 | }
337 | }
338 |
339 | /* See issue #2901 */
340 | .cm-tab-wrap-hack:after { content: ''; }
341 |
342 | /* Help users use markselection to safely style text background */
343 | span.CodeMirror-selectedtext { background: none; }
344 |
--------------------------------------------------------------------------------
/src/js/workers/formatter.js:
--------------------------------------------------------------------------------
1 | /* global globalThis, addEventListener, postMessage, BigInt */
2 |
3 | /**
4 | * Adapted the code in to order to run in a web worker.
5 | *
6 | * Original author: Benjamin Hollis
7 | */
8 |
9 | function htmlEncode(t) {
10 | return t != null ? t.toString().replace(/&/g, "&").replace(/"/g, """).replace(//g, ">") : "";
11 | }
12 |
13 | function decorateWithSpan(value, className) {
14 | return "" + htmlEncode(value) + "";
15 | }
16 |
17 | function valueToHTML(value) {
18 | const valueType = typeof value;
19 | let output = "";
20 | if (value == null)
21 | output += decorateWithSpan("null", "type-null");
22 | else if (value && value.constructor == Array)
23 | output += arrayToHTML(value);
24 | else if (valueType == "object")
25 | output += objectToHTML(value);
26 | else if (valueType == "number" || valueType == "bigint")
27 | output += decorateWithSpan(value, "type-number");
28 | else if (valueType == "string")
29 | if (/^https?:\/\/[^\s]+$/.test(value))
30 | output += decorateWithSpan("\"", "type-string") + "" + htmlEncode(value) + "" + decorateWithSpan("\"", "type-string");
31 | else
32 | output += decorateWithSpan("\"" + value + "\"", "type-string");
33 | else if (valueType == "boolean")
34 | output += decorateWithSpan(value, "type-boolean");
35 |
36 | return output;
37 | }
38 |
39 | function arrayToHTML(json) {
40 | let indexValue, length, output = "[]";
50 | if (!hasContents)
51 | output = "[ ]";
52 | return output;
53 | }
54 |
55 | function objectToHTML(json) {
56 | let indexKey, key, length, keys = Object.keys(json), output = "{}";
68 | if (!hasContents)
69 | output = "{ }";
70 | return output;
71 | }
72 |
73 | function jsonToHTML(json, functionName) {
74 | let output = "";
75 | if (functionName)
76 | output += "" + htmlEncode(functionName) + "(
";
77 | output += "";
78 | output += valueToHTML(json);
79 | output += "
";
80 | if (functionName)
81 | output += ")
";
82 | return output;
83 | }
84 |
85 | // regexpxs extracted from
86 | // (c) BSD-3-Clause
87 | // https://github.com/fastify/secure-json-parse/graphs/contributors and https://github.com/hapijs/bourne/graphs/contributors
88 |
89 | const suspectProtoRx = /(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])/;
90 | const suspectConstructorRx = /(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)/;
91 |
92 | /*
93 | json_parse.js
94 | 2012-06-20
95 |
96 | Public Domain.
97 |
98 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
99 |
100 | This file creates a json_parse function.
101 | During create you can (optionally) specify some behavioural switches
102 |
103 | require('json-bigint')(options)
104 |
105 | The optional options parameter holds switches that drive certain
106 | aspects of the parsing process:
107 | * options.strict = true will warn about duplicate-key usage in the json.
108 | The default (strict = false) will silently ignore those and overwrite
109 | values for keys that are in duplicate use.
110 |
111 | The resulting function follows this signature:
112 | json_parse(text, reviver)
113 | This method parses a JSON text to produce an object or array.
114 | It can throw a SyntaxError exception.
115 |
116 | The optional reviver parameter is a function that can filter and
117 | transform the results. It receives each of the keys and values,
118 | and its return value is used instead of the original value.
119 | If it returns what it received, then the structure is not modified.
120 | If it returns undefined then the member is deleted.
121 |
122 | Example:
123 |
124 | // Parse the text. Values that look like ISO date strings will
125 | // be converted to Date objects.
126 |
127 | myData = json_parse(text, function (key, value) {
128 | var a;
129 | if (typeof value === 'string') {
130 | a =
131 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
132 | if (a) {
133 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
134 | +a[5], +a[6]));
135 | }
136 | }
137 | return value;
138 | });
139 |
140 | This is a reference implementation. You are free to copy, modify, or
141 | redistribute.
142 |
143 | This code should be minified before deployment.
144 | See http://javascript.crockford.com/jsmin.html
145 |
146 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
147 | NOT CONTROL.
148 | */
149 |
150 | /*members "", "\"", "\/", "\\", at, b, call, charAt, f, fromCharCode,
151 | hasOwnProperty, message, n, name, prototype, push, r, t, text
152 | */
153 |
154 | var json_parse = function (options) {
155 | "use strict";
156 |
157 | // This is a function that can parse a JSON text, producing a JavaScript
158 | // data structure. It is a simple, recursive descent parser. It does not use
159 | // eval or regular expressions, so it can be used as a model for implementing
160 | // a JSON parser in other languages.
161 |
162 | // We are defining the function inside of another function to avoid creating
163 | // global variables.
164 |
165 | // Default options one can override by passing options to the parse()
166 | var _options = {
167 | strict: false, // not being strict means do not generate syntax errors for "duplicate key"
168 | storeAsString: false, // toggles whether the values should be stored as BigNumber (default) or a string
169 | alwaysParseAsBig: false, // toggles whether all numbers should be Big
170 | useNativeBigInt: false, // toggles whether to use native BigInt instead of bignumber.js
171 | protoAction: "error",
172 | constructorAction: "error",
173 | };
174 |
175 | // If there are options, then use them to override the default _options
176 | if (options !== undefined && options !== null) {
177 | if (options.strict === true) {
178 | _options.strict = true;
179 | }
180 | if (options.storeAsString === true) {
181 | _options.storeAsString = true;
182 | }
183 | _options.alwaysParseAsBig =
184 | options.alwaysParseAsBig === true ? options.alwaysParseAsBig : false;
185 | _options.useNativeBigInt =
186 | options.useNativeBigInt === true ? options.useNativeBigInt : false;
187 |
188 | if (typeof options.constructorAction !== "undefined") {
189 | if (
190 | options.constructorAction === "error" ||
191 | options.constructorAction === "ignore" ||
192 | options.constructorAction === "preserve"
193 | ) {
194 | _options.constructorAction = options.constructorAction;
195 | } else {
196 | throw new Error(
197 | `Incorrect value for constructorAction option, must be "error", "ignore" or undefined but passed ${options.constructorAction}`
198 | );
199 | }
200 | }
201 |
202 | if (typeof options.protoAction !== "undefined") {
203 | if (
204 | options.protoAction === "error" ||
205 | options.protoAction === "ignore" ||
206 | options.protoAction === "preserve"
207 | ) {
208 | _options.protoAction = options.protoAction;
209 | } else {
210 | throw new Error(
211 | `Incorrect value for protoAction option, must be "error", "ignore" or undefined but passed ${options.protoAction}`
212 | );
213 | }
214 | }
215 | }
216 |
217 | var at, // The index of the current character
218 | ch, // The current character
219 | escapee = {
220 | "\"": "\"",
221 | "\\": "\\",
222 | "/": "/",
223 | b: "\b",
224 | f: "\f",
225 | n: "\n",
226 | r: "\r",
227 | t: "\t",
228 | },
229 | text,
230 | error = function (m) {
231 | // Call error when something is wrong.
232 |
233 | throw {
234 | name: "SyntaxError",
235 | message: m,
236 | at: at,
237 | text: text,
238 | };
239 | },
240 | next = function (c) {
241 | // If a c parameter is provided, verify that it matches the current character.
242 |
243 | if (c && c !== ch) {
244 | error("Expected '" + c + "' instead of '" + ch + "'");
245 | }
246 |
247 | // Get the next character. When there are no more characters,
248 | // return the empty string.
249 |
250 | ch = text.charAt(at);
251 | at += 1;
252 | return ch;
253 | },
254 | number = function () {
255 | // Parse a number value.
256 |
257 | var number,
258 | string = "";
259 |
260 | if (ch === "-") {
261 | string = "-";
262 | next("-");
263 | }
264 | while (ch >= "0" && ch <= "9") {
265 | string += ch;
266 | next();
267 | }
268 | if (ch === ".") {
269 | string += ".";
270 | while (next() && ch >= "0" && ch <= "9") {
271 | string += ch;
272 | }
273 | }
274 | if (ch === "e" || ch === "E") {
275 | string += ch;
276 | next();
277 | if (ch === "-" || ch === "+") {
278 | string += ch;
279 | next();
280 | }
281 | while (ch >= "0" && ch <= "9") {
282 | string += ch;
283 | next();
284 | }
285 | }
286 | number = +string;
287 | if (!isFinite(number)) {
288 | error("Bad number");
289 | } else {
290 | // if (BigNumber == null) BigNumber = require("bignumber.js");
291 | if (Number.isSafeInteger(number))
292 | return !_options.alwaysParseAsBig
293 | ? number
294 | : BigInt(number);
295 | else
296 | // Number with fractional part should be treated as number(double) including big integers in scientific notation, i.e 1.79e+308
297 | return _options.storeAsString
298 | ? string
299 | : /[.eE]/.test(string)
300 | ? number
301 | : BigInt(string);
302 | }
303 | },
304 | string = function () {
305 | // Parse a string value.
306 |
307 | var hex,
308 | i,
309 | string = "",
310 | uffff;
311 |
312 | // When parsing for string values, we must look for " and \ characters.
313 |
314 | if (ch === "\"") {
315 | var startAt = at;
316 | while (next()) {
317 | if (ch === "\"") {
318 | if (at - 1 > startAt) string += text.substring(startAt, at - 1);
319 | next();
320 | return string;
321 | }
322 | if (ch === "\\") {
323 | if (at - 1 > startAt) string += text.substring(startAt, at - 1);
324 | next();
325 | if (ch === "u") {
326 | uffff = 0;
327 | for (i = 0; i < 4; i += 1) {
328 | hex = parseInt(next(), 16);
329 | if (!isFinite(hex)) {
330 | break;
331 | }
332 | uffff = uffff * 16 + hex;
333 | }
334 | string += String.fromCharCode(uffff);
335 | } else if (typeof escapee[ch] === "string") {
336 | string += escapee[ch];
337 | } else {
338 | break;
339 | }
340 | startAt = at;
341 | }
342 | }
343 | }
344 | error("Bad string");
345 | },
346 | white = function () {
347 | // Skip whitespace.
348 |
349 | while (ch && ch <= " ") {
350 | next();
351 | }
352 | },
353 | word = function () {
354 | // true, false, or null.
355 |
356 | switch (ch) {
357 | case "t":
358 | next("t");
359 | next("r");
360 | next("u");
361 | next("e");
362 | return true;
363 | case "f":
364 | next("f");
365 | next("a");
366 | next("l");
367 | next("s");
368 | next("e");
369 | return false;
370 | case "n":
371 | next("n");
372 | next("u");
373 | next("l");
374 | next("l");
375 | return null;
376 | }
377 | error("Unexpected '" + ch + "'");
378 | },
379 | value, // Place holder for the value function.
380 | array = function () {
381 | // Parse an array value.
382 |
383 | var array = [];
384 |
385 | if (ch === "[") {
386 | next("[");
387 | white();
388 | if (ch === "]") {
389 | next("]");
390 | return array; // empty array
391 | }
392 | while (ch) {
393 | array.push(value());
394 | white();
395 | if (ch === "]") {
396 | next("]");
397 | return array;
398 | }
399 | next(",");
400 | white();
401 | }
402 | }
403 | error("Bad array");
404 | },
405 | object = function () {
406 | // Parse an object value.
407 |
408 | var key,
409 | object = Object.create(null);
410 |
411 | if (ch === "{") {
412 | next("{");
413 | white();
414 | if (ch === "}") {
415 | next("}");
416 | return object; // empty object
417 | }
418 | while (ch) {
419 | key = string();
420 | white();
421 | next(":");
422 | if (
423 | _options.strict === true &&
424 | Object.hasOwnProperty.call(object, key)
425 | ) {
426 | error("Duplicate key \"" + key + "\"");
427 | }
428 |
429 | if (suspectProtoRx.test(key) === true) {
430 | if (_options.protoAction === "error") {
431 | error("Object contains forbidden prototype property");
432 | } else if (_options.protoAction === "ignore") {
433 | value();
434 | } else {
435 | object[key] = value();
436 | }
437 | } else if (suspectConstructorRx.test(key) === true) {
438 | if (_options.constructorAction === "error") {
439 | error("Object contains forbidden constructor property");
440 | } else if (_options.constructorAction === "ignore") {
441 | value();
442 | } else {
443 | object[key] = value();
444 | }
445 | } else {
446 | object[key] = value();
447 | }
448 |
449 | white();
450 | if (ch === "}") {
451 | next("}");
452 | return object;
453 | }
454 | next(",");
455 | white();
456 | }
457 | }
458 | error("Bad object");
459 | };
460 |
461 | value = function () {
462 | // Parse a JSON value. It could be an object, an array, a string, a number,
463 | // or a word.
464 |
465 | white();
466 | switch (ch) {
467 | case "{":
468 | return object();
469 | case "[":
470 | return array();
471 | case "\"":
472 | return string();
473 | case "-":
474 | return number();
475 | default:
476 | return ch >= "0" && ch <= "9" ? number() : word();
477 | }
478 | };
479 |
480 | // Return the json_parse function. It will have access to all of the above
481 | // functions and variables.
482 |
483 | return function (source, reviver) {
484 | var result;
485 |
486 | text = source + "";
487 | at = 0;
488 | ch = " ";
489 | result = value();
490 | white();
491 | if (ch) {
492 | error("Syntax error");
493 | }
494 |
495 | // If there is a reviver function, we recursively walk the new structure,
496 | // passing each name/value pair to the reviver function for possible
497 | // transformation, starting with a temporary root object that holds the result
498 | // in an empty key. If there is not a reviver function, we simply return the
499 | // result.
500 |
501 | return typeof reviver === "function"
502 | ? (function walk(holder, key) {
503 | var v,
504 | value = holder[key];
505 | if (value && typeof value === "object") {
506 | Object.keys(value).forEach(function (k) {
507 | v = walk(value, k);
508 | if (v !== undefined) {
509 | value[k] = v;
510 | } else {
511 | delete value[k];
512 | }
513 | });
514 | }
515 | return reviver.call(holder, key, value);
516 | })({ "": result }, "")
517 | : result;
518 | };
519 | };
520 |
521 | const parseJson = json_parse();
522 |
523 | function format(json, functionName, supportBigInt) {
524 | let object;
525 | if (supportBigInt) {
526 | object = parseJson(json);
527 | } else {
528 | object = JSON.parse(json);
529 | }
530 | return jsonToHTML(object, functionName);
531 | }
532 |
533 | if (typeof postMessage == "undefined") {
534 | globalThis.formatter = { format };
535 | } else {
536 | addEventListener("message", event => {
537 | try {
538 | postMessage({
539 | onjsonToHTML: true,
540 | html: format(event.data.json, event.data.functionName, event.data.supportBigInt)
541 | });
542 | } catch (error) {
543 | postMessage({ error: true });
544 | return;
545 | }
546 | }, false);
547 | }
548 |
549 |
--------------------------------------------------------------------------------
/src/js/workers/linter.js:
--------------------------------------------------------------------------------
1 | /* global globalThis, addEventListener, postMessage */
2 |
3 | /*
4 | MIT License
5 | Copyright (C) 2012 Zachary Carter
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8 |
9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 |
11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 | */
13 | /* Jison generated parser */
14 | var jsonlint = (function () {
15 | var parser = {
16 | trace: function trace() { },
17 | yy: {},
18 | symbols_: { "error": 2, "JSONString": 3, "STRING": 4, "JSONNumber": 5, "NUMBER": 6, "JSONNullLiteral": 7, "NULL": 8, "JSONBooleanLiteral": 9, "TRUE": 10, "FALSE": 11, "JSONText": 12, "JSONValue": 13, "EOF": 14, "JSONObject": 15, "JSONArray": 16, "{": 17, "}": 18, "JSONMemberList": 19, "JSONMember": 20, ":": 21, ",": 22, "[": 23, "]": 24, "JSONElementList": 25, "$accept": 0, "$end": 1 },
19 | terminals_: { 2: "error", 4: "STRING", 6: "NUMBER", 8: "NULL", 10: "TRUE", 11: "FALSE", 14: "EOF", 17: "{", 18: "}", 21: ":", 22: ",", 23: "[", 24: "]" },
20 | productions_: [0, [3, 1], [5, 1], [7, 1], [9, 1], [9, 1], [12, 2], [13, 1], [13, 1], [13, 1], [13, 1], [13, 1], [13, 1], [15, 2], [15, 3], [20, 3], [19, 1], [19, 3], [16, 2], [16, 3], [25, 1], [25, 3]],
21 | performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$) {
22 |
23 | var $0 = $$.length - 1;
24 | switch (yystate) {
25 | case 1: // replace escaped characters with actual character
26 | this.$ = yytext.replace(/\\(\\|")/g, "$" + "1")
27 | .replace(/\\n/g, "\n")
28 | .replace(/\\r/g, "\r")
29 | .replace(/\\t/g, "\t")
30 | .replace(/\\v/g, "\v")
31 | .replace(/\\f/g, "\f")
32 | .replace(/\\b/g, "\b");
33 |
34 | break;
35 | case 2: this.$ = Number(yytext);
36 | break;
37 | case 3: this.$ = null;
38 | break;
39 | case 4: this.$ = true;
40 | break;
41 | case 5: this.$ = false;
42 | break;
43 | case 6: return this.$ = $$[$0 - 1];
44 | case 13: this.$ = {};
45 | break;
46 | case 14: this.$ = $$[$0 - 1];
47 | break;
48 | case 15: this.$ = [$$[$0 - 2], $$[$0]];
49 | break;
50 | case 16: this.$ = {}; this.$[$$[$0][0]] = $$[$0][1];
51 | break;
52 | case 17: this.$ = $$[$0 - 2]; $$[$0 - 2][$$[$0][0]] = $$[$0][1];
53 | break;
54 | case 18: this.$ = [];
55 | break;
56 | case 19: this.$ = $$[$0 - 1];
57 | break;
58 | case 20: this.$ = [$$[$0]];
59 | break;
60 | case 21: this.$ = $$[$0 - 2]; $$[$0 - 2].push($$[$0]);
61 | break;
62 | }
63 | },
64 | table: [{ 3: 5, 4: [1, 12], 5: 6, 6: [1, 13], 7: 3, 8: [1, 9], 9: 4, 10: [1, 10], 11: [1, 11], 12: 1, 13: 2, 15: 7, 16: 8, 17: [1, 14], 23: [1, 15] }, { 1: [3] }, { 14: [1, 16] }, { 14: [2, 7], 18: [2, 7], 22: [2, 7], 24: [2, 7] }, { 14: [2, 8], 18: [2, 8], 22: [2, 8], 24: [2, 8] }, { 14: [2, 9], 18: [2, 9], 22: [2, 9], 24: [2, 9] }, { 14: [2, 10], 18: [2, 10], 22: [2, 10], 24: [2, 10] }, { 14: [2, 11], 18: [2, 11], 22: [2, 11], 24: [2, 11] }, { 14: [2, 12], 18: [2, 12], 22: [2, 12], 24: [2, 12] }, { 14: [2, 3], 18: [2, 3], 22: [2, 3], 24: [2, 3] }, { 14: [2, 4], 18: [2, 4], 22: [2, 4], 24: [2, 4] }, { 14: [2, 5], 18: [2, 5], 22: [2, 5], 24: [2, 5] }, { 14: [2, 1], 18: [2, 1], 21: [2, 1], 22: [2, 1], 24: [2, 1] }, { 14: [2, 2], 18: [2, 2], 22: [2, 2], 24: [2, 2] }, { 3: 20, 4: [1, 12], 18: [1, 17], 19: 18, 20: 19 }, { 3: 5, 4: [1, 12], 5: 6, 6: [1, 13], 7: 3, 8: [1, 9], 9: 4, 10: [1, 10], 11: [1, 11], 13: 23, 15: 7, 16: 8, 17: [1, 14], 23: [1, 15], 24: [1, 21], 25: 22 }, { 1: [2, 6] }, { 14: [2, 13], 18: [2, 13], 22: [2, 13], 24: [2, 13] }, { 18: [1, 24], 22: [1, 25] }, { 18: [2, 16], 22: [2, 16] }, { 21: [1, 26] }, { 14: [2, 18], 18: [2, 18], 22: [2, 18], 24: [2, 18] }, { 22: [1, 28], 24: [1, 27] }, { 22: [2, 20], 24: [2, 20] }, { 14: [2, 14], 18: [2, 14], 22: [2, 14], 24: [2, 14] }, { 3: 20, 4: [1, 12], 20: 29 }, { 3: 5, 4: [1, 12], 5: 6, 6: [1, 13], 7: 3, 8: [1, 9], 9: 4, 10: [1, 10], 11: [1, 11], 13: 30, 15: 7, 16: 8, 17: [1, 14], 23: [1, 15] }, { 14: [2, 19], 18: [2, 19], 22: [2, 19], 24: [2, 19] }, { 3: 5, 4: [1, 12], 5: 6, 6: [1, 13], 7: 3, 8: [1, 9], 9: 4, 10: [1, 10], 11: [1, 11], 13: 31, 15: 7, 16: 8, 17: [1, 14], 23: [1, 15] }, { 18: [2, 17], 22: [2, 17] }, { 18: [2, 15], 22: [2, 15] }, { 22: [2, 21], 24: [2, 21] }],
65 | defaultActions: { 16: [2, 6] },
66 | parseError: function parseError(str) {
67 | throw new Error(str);
68 | },
69 | parse: function parse(input) {
70 | var self = this,
71 | stack = [0],
72 | vstack = [null], // semantic value stack
73 | lstack = [], // location stack
74 | table = this.table,
75 | yytext = "",
76 | yylineno = 0,
77 | yyleng = 0,
78 | recovering = 0,
79 | TERROR = 2,
80 | EOF = 1;
81 |
82 | //this.reductionCount = this.shiftCount = 0;
83 |
84 | this.lexer.setInput(input);
85 | this.lexer.yy = this.yy;
86 | this.yy.lexer = this.lexer;
87 | if (typeof this.lexer.yylloc == "undefined")
88 | this.lexer.yylloc = {};
89 | var yyloc = this.lexer.yylloc;
90 | lstack.push(yyloc);
91 |
92 | if (typeof this.yy.parseError === "function")
93 | this.parseError = this.yy.parseError;
94 |
95 | function popStack(n) {
96 | stack.length = stack.length - 2 * n;
97 | vstack.length = vstack.length - n;
98 | lstack.length = lstack.length - n;
99 | }
100 |
101 | function lex() {
102 | var token;
103 | token = self.lexer.lex() || 1; // $end = 1
104 | // if token isn't its numeric value, convert
105 | if (typeof token !== "number") {
106 | token = self.symbols_[token] || token;
107 | }
108 | return token;
109 | }
110 |
111 | var symbol, preErrorSymbol, state, action, r, yyval = {}, p, len, newState, expected;
112 | // eslint-disable-next-line no-constant-condition
113 | while (true) {
114 | // retreive state number from top of stack
115 | state = stack[stack.length - 1];
116 |
117 | // use default actions if available
118 | if (this.defaultActions[state]) {
119 | action = this.defaultActions[state];
120 | } else {
121 | if (symbol == null)
122 | symbol = lex();
123 | // read action for current state and first input
124 | action = table[state] && table[state][symbol];
125 | }
126 |
127 | // handle parse error
128 | if (typeof action === "undefined" || !action.length || !action[0]) {
129 |
130 | if (!recovering) {
131 | // Report error
132 | expected = [];
133 | for (p in table[state]) if (this.terminals_[p] && p > 2) {
134 | expected.push("'" + this.terminals_[p] + "'");
135 | }
136 | var errStr = "";
137 | if (this.lexer.showPosition) {
138 | errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + this.terminals_[symbol] + "'";
139 | } else {
140 | errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " +
141 | (symbol == 1 /*EOF*/ ? "end of input" : ("'" + (this.terminals_[symbol] || symbol) + "'"));
142 | }
143 | this.parseError(errStr,
144 | { text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected });
145 | }
146 |
147 | // just recovered from another error
148 | if (recovering == 3) {
149 | if (symbol == EOF) {
150 | throw new Error(errStr || "Parsing halted.");
151 | }
152 |
153 | // discard current lookahead and grab another
154 | yyleng = this.lexer.yyleng;
155 | yytext = this.lexer.yytext;
156 | yylineno = this.lexer.yylineno;
157 | yyloc = this.lexer.yylloc;
158 | symbol = lex();
159 | }
160 |
161 | // try to recover from error
162 | // eslint-disable-next-line no-constant-condition
163 | while (true) {
164 | // check for error recovery rule in this state
165 | if ((TERROR.toString()) in table[state]) {
166 | break;
167 | }
168 | if (state == 0) {
169 | throw new Error(errStr || "Parsing halted.");
170 | }
171 | popStack(1);
172 | state = stack[stack.length - 1];
173 | }
174 |
175 | preErrorSymbol = symbol; // save the lookahead token
176 | symbol = TERROR; // insert generic error symbol as new lookahead
177 | state = stack[stack.length - 1];
178 | action = table[state] && table[state][TERROR];
179 | recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
180 | }
181 |
182 | // this shouldn't happen, unless resolve defaults are off
183 | if (action[0] instanceof Array && action.length > 1) {
184 | throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
185 | }
186 |
187 | switch (action[0]) {
188 |
189 | case 1: // shift
190 | //this.shiftCount++;
191 |
192 | stack.push(symbol);
193 | vstack.push(this.lexer.yytext);
194 | lstack.push(this.lexer.yylloc);
195 | stack.push(action[1]); // push state
196 | symbol = null;
197 | if (!preErrorSymbol) { // normal execution/no error
198 | yyleng = this.lexer.yyleng;
199 | yytext = this.lexer.yytext;
200 | yylineno = this.lexer.yylineno;
201 | yyloc = this.lexer.yylloc;
202 | if (recovering > 0)
203 | recovering--;
204 | } else { // error just occurred, resume old lookahead f/ before error
205 | symbol = preErrorSymbol;
206 | preErrorSymbol = null;
207 | }
208 | break;
209 |
210 | case 2: // reduce
211 | //this.reductionCount++;
212 |
213 | len = this.productions_[action[1]][1];
214 |
215 | // perform semantic action
216 | yyval.$ = vstack[vstack.length - len]; // default to $$ = $1
217 | // default location, uses first token for firsts, last for lasts
218 | yyval._$ = {
219 | first_line: lstack[lstack.length - (len || 1)].first_line,
220 | last_line: lstack[lstack.length - 1].last_line,
221 | first_column: lstack[lstack.length - (len || 1)].first_column,
222 | last_column: lstack[lstack.length - 1].last_column
223 | };
224 | r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
225 |
226 | if (typeof r !== "undefined") {
227 | return r;
228 | }
229 |
230 | // pop off stack
231 | if (len) {
232 | stack = stack.slice(0, -1 * len * 2);
233 | vstack = vstack.slice(0, -1 * len);
234 | lstack = lstack.slice(0, -1 * len);
235 | }
236 |
237 | stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)
238 | vstack.push(yyval.$);
239 | lstack.push(yyval._$);
240 | // goto new state = table[STATE][NONTERMINAL]
241 | newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
242 | stack.push(newState);
243 | break;
244 |
245 | case 3: // accept
246 | return true;
247 | }
248 |
249 | }
250 | }
251 | };
252 | /* Jison generated lexer */
253 | var lexer = (function () {
254 | var lexer = ({
255 | EOF: 1,
256 | parseError: function parseError(str, hash) {
257 | if (this.yy.parseError) {
258 | this.yy.parseError(str, hash);
259 | } else {
260 | throw new Error(str);
261 | }
262 | },
263 | setInput: function (input) {
264 | this._input = input;
265 | this._more = this._less = this.done = false;
266 | this.yylineno = this.yyleng = 0;
267 | this.yytext = this.matched = this.match = "";
268 | this.conditionStack = ["INITIAL"];
269 | this.yylloc = { first_line: 1, first_column: 0, last_line: 1, last_column: 0 };
270 | return this;
271 | },
272 | input: function () {
273 | var ch = this._input[0];
274 | this.yytext += ch;
275 | this.yyleng++;
276 | this.match += ch;
277 | this.matched += ch;
278 | var lines = ch.match(/\n/);
279 | if (lines) this.yylineno++;
280 | this._input = this._input.slice(1);
281 | return ch;
282 | },
283 | unput: function (ch) {
284 | this._input = ch + this._input;
285 | return this;
286 | },
287 | more: function () {
288 | this._more = true;
289 | return this;
290 | },
291 | less: function (n) {
292 | this._input = this.match.slice(n) + this._input;
293 | },
294 | pastInput: function () {
295 | var past = this.matched.substr(0, this.matched.length - this.match.length);
296 | return (past.length > 20 ? "..." : "") + past.substr(-20).replace(/\n/g, "");
297 | },
298 | upcomingInput: function () {
299 | var next = this.match;
300 | if (next.length < 20) {
301 | next += this._input.substr(0, 20 - next.length);
302 | }
303 | return (next.substr(0, 20) + (next.length > 20 ? "..." : "")).replace(/\n/g, "");
304 | },
305 | showPosition: function () {
306 | var pre = this.pastInput();
307 | var c = new Array(pre.length + 1).join("-");
308 | return pre + this.upcomingInput() + "\n" + c + "^";
309 | },
310 | next: function () {
311 | if (this.done) {
312 | return this.EOF;
313 | }
314 | if (!this._input) this.done = true;
315 |
316 | var token,
317 | match,
318 | tempMatch,
319 | index,
320 | lines;
321 | if (!this._more) {
322 | this.yytext = "";
323 | this.match = "";
324 | }
325 | var rules = this._currentRules();
326 | for (var i = 0; i < rules.length; i++) {
327 | tempMatch = this._input.match(this.rules[rules[i]]);
328 | if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
329 | match = tempMatch;
330 | index = i;
331 | if (!this.options.flex) break;
332 | }
333 | }
334 | if (match) {
335 | lines = match[0].match(/\n.*/g);
336 | if (lines) this.yylineno += lines.length;
337 | this.yylloc = {
338 | first_line: this.yylloc.last_line,
339 | last_line: this.yylineno + 1,
340 | first_column: this.yylloc.last_column,
341 | last_column: lines ? lines[lines.length - 1].length - 1 : this.yylloc.last_column + match[0].length
342 | };
343 | this.yytext += match[0];
344 | this.match += match[0];
345 | this.yyleng = this.yytext.length;
346 | this._more = false;
347 | this._input = this._input.slice(match[0].length);
348 | this.matched += match[0];
349 | token = this.performAction.call(this, this.yy, this, rules[index], this.conditionStack[this.conditionStack.length - 1]);
350 | if (this.done && this._input) this.done = false;
351 | if (token) return token;
352 | else return;
353 | }
354 | if (this._input === "") {
355 | return this.EOF;
356 | } else {
357 | this.parseError("Lexical error on line " + (this.yylineno + 1) + ". Unrecognized text.\n" + this.showPosition(),
358 | { text: "", token: null, line: this.yylineno });
359 | }
360 | },
361 | lex: function lex() {
362 | var r = this.next();
363 | if (typeof r !== "undefined") {
364 | return r;
365 | } else {
366 | return this.lex();
367 | }
368 | },
369 | begin: function begin(condition) {
370 | this.conditionStack.push(condition);
371 | },
372 | popState: function popState() {
373 | return this.conditionStack.pop();
374 | },
375 | _currentRules: function _currentRules() {
376 | return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
377 | },
378 | topState: function () {
379 | return this.conditionStack[this.conditionStack.length - 2];
380 | },
381 | pushState: function begin(condition) {
382 | this.begin(condition);
383 | }
384 | });
385 | lexer.options = {};
386 | lexer.performAction = function anonymous(yy, yy_, $avoiding_name_collisions) {
387 | switch ($avoiding_name_collisions) {
388 | case 0:/* skip whitespace */
389 | break;
390 | case 1: return 6;
391 | case 2: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng - 2); return 4;
392 | case 3: return 17;
393 | case 4: return 18;
394 | case 5: return 23;
395 | case 6: return 24;
396 | case 7: return 22;
397 | case 8: return 21;
398 | case 9: return 10;
399 | case 10: return 11;
400 | case 11: return 8;
401 | case 12: return 14;
402 | case 13: return "INVALID";
403 | }
404 | };
405 | // eslint-disable-next-line no-control-regex
406 | lexer.rules = [/^(?:\s+)/, /^(?:(-?([0-9]|[1-9][0-9]+))(\.[0-9]+)?([eE][-+]?[0-9]+)?\b)/, /^(?:"(?:\\[\\"bfnrt/]|\\u[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*")/, /^(?:\{)/, /^(?:\})/, /^(?:\[)/, /^(?:\])/, /^(?:,)/, /^(?::)/, /^(?:true\b)/, /^(?:false\b)/, /^(?:null\b)/, /^(?:$)/, /^(?:.)/];
407 | lexer.conditions = { "INITIAL": { "rules": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "inclusive": true } };
408 |
409 |
410 |
411 | return lexer;
412 | })();
413 | parser.lexer = lexer;
414 | return parser;
415 | })();
416 |
417 | function lint(json) {
418 | try {
419 | jsonlint.parse(json);
420 | return {};
421 | } catch (errorMessage) {
422 | return { error: errorMessage.toString(), loc: jsonlint.lexer.yylloc };
423 | }
424 | }
425 |
426 | if (typeof postMessage == "undefined") {
427 | globalThis.linter = { lint };
428 | } else {
429 | addEventListener("message", event => postMessage(lint(event.data)), false);
430 | }
--------------------------------------------------------------------------------
/src/js/workers/parser.js:
--------------------------------------------------------------------------------
1 | /* global globalThis, addEventListener, postMessage, BigInt */
2 |
3 | // regexpxs extracted from
4 | // (c) BSD-3-Clause
5 | // https://github.com/fastify/secure-json-parse/graphs/contributors and https://github.com/hapijs/bourne/graphs/contributors
6 |
7 | const suspectProtoRx = /(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])/;
8 | const suspectConstructorRx = /(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)/;
9 |
10 | /*
11 | json_parse.js
12 | 2012-06-20
13 |
14 | Public Domain.
15 |
16 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
17 |
18 | This file creates a json_parse function.
19 | During create you can (optionally) specify some behavioural switches
20 |
21 | require('json-bigint')(options)
22 |
23 | The optional options parameter holds switches that drive certain
24 | aspects of the parsing process:
25 | * options.strict = true will warn about duplicate-key usage in the json.
26 | The default (strict = false) will silently ignore those and overwrite
27 | values for keys that are in duplicate use.
28 |
29 | The resulting function follows this signature:
30 | json_parse(text, reviver)
31 | This method parses a JSON text to produce an object or array.
32 | It can throw a SyntaxError exception.
33 |
34 | The optional reviver parameter is a function that can filter and
35 | transform the results. It receives each of the keys and values,
36 | and its return value is used instead of the original value.
37 | If it returns what it received, then the structure is not modified.
38 | If it returns undefined then the member is deleted.
39 |
40 | Example:
41 |
42 | // Parse the text. Values that look like ISO date strings will
43 | // be converted to Date objects.
44 |
45 | myData = json_parse(text, function (key, value) {
46 | var a;
47 | if (typeof value === 'string') {
48 | a =
49 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
50 | if (a) {
51 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
52 | +a[5], +a[6]));
53 | }
54 | }
55 | return value;
56 | });
57 |
58 | This is a reference implementation. You are free to copy, modify, or
59 | redistribute.
60 |
61 | This code should be minified before deployment.
62 | See http://javascript.crockford.com/jsmin.html
63 |
64 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
65 | NOT CONTROL.
66 | */
67 |
68 | /*members "", "\"", "\/", "\\", at, b, call, charAt, f, fromCharCode,
69 | hasOwnProperty, message, n, name, prototype, push, r, t, text
70 | */
71 |
72 | var json_parse = function (options) {
73 | "use strict";
74 |
75 | // This is a function that can parse a JSON text, producing a JavaScript
76 | // data structure. It is a simple, recursive descent parser. It does not use
77 | // eval or regular expressions, so it can be used as a model for implementing
78 | // a JSON parser in other languages.
79 |
80 | // We are defining the function inside of another function to avoid creating
81 | // global variables.
82 |
83 | // Default options one can override by passing options to the parse()
84 | var _options = {
85 | strict: false, // not being strict means do not generate syntax errors for "duplicate key"
86 | storeAsString: false, // toggles whether the values should be stored as BigNumber (default) or a string
87 | alwaysParseAsBig: false, // toggles whether all numbers should be Big
88 | useNativeBigInt: false, // toggles whether to use native BigInt instead of bignumber.js
89 | protoAction: "error",
90 | constructorAction: "error",
91 | };
92 |
93 | // If there are options, then use them to override the default _options
94 | if (options !== undefined && options !== null) {
95 | if (options.strict === true) {
96 | _options.strict = true;
97 | }
98 | if (options.storeAsString === true) {
99 | _options.storeAsString = true;
100 | }
101 | _options.alwaysParseAsBig =
102 | options.alwaysParseAsBig === true ? options.alwaysParseAsBig : false;
103 | _options.useNativeBigInt =
104 | options.useNativeBigInt === true ? options.useNativeBigInt : false;
105 |
106 | if (typeof options.constructorAction !== "undefined") {
107 | if (
108 | options.constructorAction === "error" ||
109 | options.constructorAction === "ignore" ||
110 | options.constructorAction === "preserve"
111 | ) {
112 | _options.constructorAction = options.constructorAction;
113 | } else {
114 | throw new Error(
115 | `Incorrect value for constructorAction option, must be "error", "ignore" or undefined but passed ${options.constructorAction}`
116 | );
117 | }
118 | }
119 |
120 | if (typeof options.protoAction !== "undefined") {
121 | if (
122 | options.protoAction === "error" ||
123 | options.protoAction === "ignore" ||
124 | options.protoAction === "preserve"
125 | ) {
126 | _options.protoAction = options.protoAction;
127 | } else {
128 | throw new Error(
129 | `Incorrect value for protoAction option, must be "error", "ignore" or undefined but passed ${options.protoAction}`
130 | );
131 | }
132 | }
133 | }
134 |
135 | var at, // The index of the current character
136 | ch, // The current character
137 | escapee = {
138 | "\"": "\"",
139 | "\\": "\\",
140 | "/": "/",
141 | b: "\b",
142 | f: "\f",
143 | n: "\n",
144 | r: "\r",
145 | t: "\t",
146 | },
147 | text,
148 | error = function (m) {
149 | // Call error when something is wrong.
150 |
151 | throw {
152 | name: "SyntaxError",
153 | message: m,
154 | at: at,
155 | text: text,
156 | };
157 | },
158 | next = function (c) {
159 | // If a c parameter is provided, verify that it matches the current character.
160 |
161 | if (c && c !== ch) {
162 | error("Expected '" + c + "' instead of '" + ch + "'");
163 | }
164 |
165 | // Get the next character. When there are no more characters,
166 | // return the empty string.
167 |
168 | ch = text.charAt(at);
169 | at += 1;
170 | return ch;
171 | },
172 | number = function () {
173 | // Parse a number value.
174 |
175 | var number,
176 | string = "";
177 |
178 | if (ch === "-") {
179 | string = "-";
180 | next("-");
181 | }
182 | while (ch >= "0" && ch <= "9") {
183 | string += ch;
184 | next();
185 | }
186 | if (ch === ".") {
187 | string += ".";
188 | while (next() && ch >= "0" && ch <= "9") {
189 | string += ch;
190 | }
191 | }
192 | if (ch === "e" || ch === "E") {
193 | string += ch;
194 | next();
195 | if (ch === "-" || ch === "+") {
196 | string += ch;
197 | next();
198 | }
199 | while (ch >= "0" && ch <= "9") {
200 | string += ch;
201 | next();
202 | }
203 | }
204 | number = +string;
205 | if (!isFinite(number)) {
206 | error("Bad number");
207 | } else {
208 | // if (BigNumber == null) BigNumber = require("bignumber.js");
209 | if (Number.isSafeInteger(number))
210 | return !_options.alwaysParseAsBig
211 | ? number
212 | : BigInt(number);
213 | else
214 | // Number with fractional part should be treated as number(double) including big integers in scientific notation, i.e 1.79e+308
215 | return _options.storeAsString
216 | ? string
217 | : /[.eE]/.test(string)
218 | ? number
219 | : BigInt(string);
220 | }
221 | },
222 | string = function () {
223 | // Parse a string value.
224 |
225 | var hex,
226 | i,
227 | string = "",
228 | uffff;
229 |
230 | // When parsing for string values, we must look for " and \ characters.
231 |
232 | if (ch === "\"") {
233 | var startAt = at;
234 | while (next()) {
235 | if (ch === "\"") {
236 | if (at - 1 > startAt) string += text.substring(startAt, at - 1);
237 | next();
238 | return string;
239 | }
240 | if (ch === "\\") {
241 | if (at - 1 > startAt) string += text.substring(startAt, at - 1);
242 | next();
243 | if (ch === "u") {
244 | uffff = 0;
245 | for (i = 0; i < 4; i += 1) {
246 | hex = parseInt(next(), 16);
247 | if (!isFinite(hex)) {
248 | break;
249 | }
250 | uffff = uffff * 16 + hex;
251 | }
252 | string += String.fromCharCode(uffff);
253 | } else if (typeof escapee[ch] === "string") {
254 | string += escapee[ch];
255 | } else {
256 | break;
257 | }
258 | startAt = at;
259 | }
260 | }
261 | }
262 | error("Bad string");
263 | },
264 | white = function () {
265 | // Skip whitespace.
266 |
267 | while (ch && ch <= " ") {
268 | next();
269 | }
270 | },
271 | word = function () {
272 | // true, false, or null.
273 |
274 | switch (ch) {
275 | case "t":
276 | next("t");
277 | next("r");
278 | next("u");
279 | next("e");
280 | return true;
281 | case "f":
282 | next("f");
283 | next("a");
284 | next("l");
285 | next("s");
286 | next("e");
287 | return false;
288 | case "n":
289 | next("n");
290 | next("u");
291 | next("l");
292 | next("l");
293 | return null;
294 | }
295 | error("Unexpected '" + ch + "'");
296 | },
297 | value, // Place holder for the value function.
298 | array = function () {
299 | // Parse an array value.
300 |
301 | var array = [];
302 |
303 | if (ch === "[") {
304 | next("[");
305 | white();
306 | if (ch === "]") {
307 | next("]");
308 | return array; // empty array
309 | }
310 | while (ch) {
311 | array.push(value());
312 | white();
313 | if (ch === "]") {
314 | next("]");
315 | return array;
316 | }
317 | next(",");
318 | white();
319 | }
320 | }
321 | error("Bad array");
322 | },
323 | object = function () {
324 | // Parse an object value.
325 |
326 | var key,
327 | object = Object.create(null);
328 |
329 | if (ch === "{") {
330 | next("{");
331 | white();
332 | if (ch === "}") {
333 | next("}");
334 | return object; // empty object
335 | }
336 | while (ch) {
337 | key = string();
338 | white();
339 | next(":");
340 | if (
341 | _options.strict === true &&
342 | Object.hasOwnProperty.call(object, key)
343 | ) {
344 | error("Duplicate key \"" + key + "\"");
345 | }
346 |
347 | if (suspectProtoRx.test(key) === true) {
348 | if (_options.protoAction === "error") {
349 | error("Object contains forbidden prototype property");
350 | } else if (_options.protoAction === "ignore") {
351 | value();
352 | } else {
353 | object[key] = value();
354 | }
355 | } else if (suspectConstructorRx.test(key) === true) {
356 | if (_options.constructorAction === "error") {
357 | error("Object contains forbidden constructor property");
358 | } else if (_options.constructorAction === "ignore") {
359 | value();
360 | } else {
361 | object[key] = value();
362 | }
363 | } else {
364 | object[key] = value();
365 | }
366 |
367 | white();
368 | if (ch === "}") {
369 | next("}");
370 | return object;
371 | }
372 | next(",");
373 | white();
374 | }
375 | }
376 | error("Bad object");
377 | };
378 |
379 | value = function () {
380 | // Parse a JSON value. It could be an object, an array, a string, a number,
381 | // or a word.
382 |
383 | white();
384 | switch (ch) {
385 | case "{":
386 | return object();
387 | case "[":
388 | return array();
389 | case "\"":
390 | return string();
391 | case "-":
392 | return number();
393 | default:
394 | return ch >= "0" && ch <= "9" ? number() : word();
395 | }
396 | };
397 |
398 | // Return the json_parse function. It will have access to all of the above
399 | // functions and variables.
400 |
401 | return function (source, reviver) {
402 | var result;
403 |
404 | text = source + "";
405 | at = 0;
406 | ch = " ";
407 | result = value();
408 | white();
409 | if (ch) {
410 | error("Syntax error");
411 | }
412 |
413 | // If there is a reviver function, we recursively walk the new structure,
414 | // passing each name/value pair to the reviver function for possible
415 | // transformation, starting with a temporary root object that holds the result
416 | // in an empty key. If there is not a reviver function, we simply return the
417 | // result.
418 |
419 | return typeof reviver === "function"
420 | ? (function walk(holder, key) {
421 | var v,
422 | value = holder[key];
423 | if (value && typeof value === "object") {
424 | Object.keys(value).forEach(function (k) {
425 | v = walk(value, k);
426 | if (v !== undefined) {
427 | value[k] = v;
428 | } else {
429 | delete value[k];
430 | }
431 | });
432 | }
433 | return reviver.call(holder, key, value);
434 | })({ "": result }, "")
435 | : result;
436 | };
437 | };
438 |
439 | /*
440 | json2.js
441 | 2013-05-26
442 |
443 | Public Domain.
444 |
445 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
446 |
447 | See http://www.JSON.org/js.html
448 |
449 |
450 | This code should be minified before deployment.
451 | See http://javascript.crockford.com/jsmin.html
452 |
453 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
454 | NOT CONTROL.
455 |
456 |
457 | This file creates a global JSON object containing two methods: stringify
458 | and parse.
459 |
460 | JSON.stringify(value, replacer, space)
461 | value any JavaScript value, usually an object or array.
462 |
463 | replacer an optional parameter that determines how object
464 | values are stringified for objects. It can be a
465 | function or an array of strings.
466 |
467 | space an optional parameter that specifies the indentation
468 | of nested structures. If it is omitted, the text will
469 | be packed without extra whitespace. If it is a number,
470 | it will specify the number of spaces to indent at each
471 | level. If it is a string (such as '\t' or ' '),
472 | it contains the characters used to indent at each level.
473 |
474 | This method produces a JSON text from a JavaScript value.
475 |
476 | When an object value is found, if the object contains a toJSON
477 | method, its toJSON method will be called and the result will be
478 | stringified. A toJSON method does not serialize: it returns the
479 | value represented by the name/value pair that should be serialized,
480 | or undefined if nothing should be serialized. The toJSON method
481 | will be passed the key associated with the value, and this will be
482 | bound to the value
483 |
484 | For example, this would serialize Dates as ISO strings.
485 |
486 | Date.prototype.toJSON = function (key) {
487 | function f(n) {
488 | // Format integers to have at least two digits.
489 | return n < 10 ? '0' + n : n;
490 | }
491 |
492 | return this.getUTCFullYear() + '-' +
493 | f(this.getUTCMonth() + 1) + '-' +
494 | f(this.getUTCDate()) + 'T' +
495 | f(this.getUTCHours()) + ':' +
496 | f(this.getUTCMinutes()) + ':' +
497 | f(this.getUTCSeconds()) + 'Z';
498 | };
499 |
500 | You can provide an optional replacer method. It will be passed the
501 | key and value of each member, with this bound to the containing
502 | object. The value that is returned from your method will be
503 | serialized. If your method returns undefined, then the member will
504 | be excluded from the serialization.
505 |
506 | If the replacer parameter is an array of strings, then it will be
507 | used to select the members to be serialized. It filters the results
508 | such that only members with keys listed in the replacer array are
509 | stringified.
510 |
511 | Values that do not have JSON representations, such as undefined or
512 | functions, will not be serialized. Such values in objects will be
513 | dropped; in arrays they will be replaced with null. You can use
514 | a replacer function to replace those with JSON values.
515 | JSON.stringify(undefined) returns undefined.
516 |
517 | The optional space parameter produces a stringification of the
518 | value that is filled with line breaks and indentation to make it
519 | easier to read.
520 |
521 | If the space parameter is a non-empty string, then that string will
522 | be used for indentation. If the space parameter is a number, then
523 | the indentation will be that many spaces.
524 |
525 | Example:
526 |
527 | text = JSON.stringify(['e', {pluribus: 'unum'}]);
528 | // text is '["e",{"pluribus":"unum"}]'
529 |
530 |
531 | text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
532 | // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
533 |
534 | text = JSON.stringify([new Date()], function (key, value) {
535 | return this[key] instanceof Date ?
536 | 'Date(' + this[key] + ')' : value;
537 | });
538 | // text is '["Date(---current time---)"]'
539 |
540 |
541 | JSON.parse(text, reviver)
542 | This method parses a JSON text to produce an object or array.
543 | It can throw a SyntaxError exception.
544 |
545 | The optional reviver parameter is a function that can filter and
546 | transform the results. It receives each of the keys and values,
547 | and its return value is used instead of the original value.
548 | If it returns what it received, then the structure is not modified.
549 | If it returns undefined then the member is deleted.
550 |
551 | Example:
552 |
553 | // Parse the text. Values that look like ISO date strings will
554 | // be converted to Date objects.
555 |
556 | myData = JSON.parse(text, function (key, value) {
557 | var a;
558 | if (typeof value === 'string') {
559 | a =
560 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
561 | if (a) {
562 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
563 | +a[5], +a[6]));
564 | }
565 | }
566 | return value;
567 | });
568 |
569 | myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
570 | var d;
571 | if (typeof value === 'string' &&
572 | value.slice(0, 5) === 'Date(' &&
573 | value.slice(-1) === ')') {
574 | d = new Date(value.slice(5, -1));
575 | if (d) {
576 | return d;
577 | }
578 | }
579 | return value;
580 | });
581 |
582 |
583 | This is a reference implementation. You are free to copy, modify, or
584 | redistribute.
585 | */
586 |
587 | /*jslint evil: true, regexp: true */
588 |
589 | /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
590 | call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
591 | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
592 | lastIndex, length, parse, prototype, push, replace, slice, stringify,
593 | test, toJSON, toString, valueOf
594 | */
595 |
596 |
597 | // Create a JSON object only if one does not already exist. We create the
598 | // methods in a closure to avoid creating global variables.
599 |
600 | (function () {
601 | "use strict";
602 |
603 | // eslint-disable-next-line no-control-regex, no-misleading-character-class, no-useless-escape
604 | var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
605 | gap,
606 | indent,
607 | meta = { // table of character substitutions
608 | "\b": "\\b",
609 | "\t": "\\t",
610 | "\n": "\\n",
611 | "\f": "\\f",
612 | "\r": "\\r",
613 | "\"": "\\\"",
614 | "\\": "\\\\"
615 | },
616 | rep;
617 |
618 |
619 | function quote(string) {
620 |
621 | // If the string contains no control characters, no quote characters, and no
622 | // backslash characters, then we can safely slap some quotes around it.
623 | // Otherwise we must also replace the offending characters with safe escape
624 | // sequences.
625 |
626 | escapable.lastIndex = 0;
627 | return escapable.test(string) ? "\"" + string.replace(escapable, function (a) {
628 | var c = meta[a];
629 | return typeof c === "string"
630 | ? c
631 | : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
632 | }) + "\"" : "\"" + string + "\"";
633 | }
634 |
635 |
636 | function str(key, holder) {
637 |
638 | // Produce a string from holder[key].
639 |
640 | var i, // The loop counter.
641 | k, // The member key.
642 | v, // The member value.
643 | length,
644 | mind = gap,
645 | partial,
646 | value = holder[key],
647 | // eslint-disable-next-line valid-typeof
648 | isBigInt = value != null && (typeof value == "bitint");
649 |
650 | // If the value has a toJSON method, call it to obtain a replacement value.
651 |
652 | if (value && typeof value === "object" &&
653 | typeof value.toJSON === "function") {
654 | value = value.toJSON(key);
655 | }
656 |
657 | // If we were called with a replacer function, then call the replacer to
658 | // obtain a replacement value.
659 |
660 | if (typeof rep === "function") {
661 | value = rep.call(holder, key, value);
662 | }
663 |
664 | // What happens next depends on the value's type.
665 |
666 | switch (typeof value) {
667 | case "string":
668 | if (isBigInt) {
669 | return value;
670 | } else {
671 | return quote(value);
672 | }
673 |
674 | case "number":
675 |
676 | // JSON numbers must be finite. Encode non-finite numbers as null.
677 |
678 | return isFinite(value) ? String(value) : "null";
679 |
680 | case "boolean":
681 | case "null":
682 | case "bigint":
683 |
684 | // If the value is a boolean or null, convert it to a string. Note:
685 | // typeof null does not produce 'null'. The case is included here in
686 | // the remote chance that this gets fixed someday.
687 |
688 | return String(value);
689 |
690 | // If the type is 'object', we might be dealing with an object or an array or
691 | // null.
692 |
693 | case "object":
694 |
695 | // Due to a specification blunder in ECMAScript, typeof null is 'object',
696 | // so watch out for that case.
697 |
698 | if (!value) {
699 | return "null";
700 | }
701 |
702 | // Make an array to hold the partial results of stringifying this object value.
703 |
704 | gap += indent;
705 | partial = [];
706 |
707 | // Is the value an array?
708 |
709 | if (Object.prototype.toString.apply(value) === "[object Array]") {
710 |
711 | // The value is an array. Stringify every element. Use null as a placeholder
712 | // for non-JSON values.
713 |
714 | length = value.length;
715 | for (i = 0; i < length; i += 1) {
716 | partial[i] = str(i, value) || "null";
717 | }
718 |
719 | // Join all of the elements together, separated with commas, and wrap them in
720 | // brackets.
721 |
722 | v = partial.length === 0
723 | ? "[]"
724 | : gap
725 | ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]"
726 | : "[" + partial.join(",") + "]";
727 | gap = mind;
728 | return v;
729 | }
730 |
731 | // If the replacer is an array, use it to select the members to be stringified.
732 |
733 | if (rep && typeof rep === "object") {
734 | length = rep.length;
735 | for (i = 0; i < length; i += 1) {
736 | if (typeof rep[i] === "string") {
737 | k = rep[i];
738 | v = str(k, value);
739 | if (v) {
740 | partial.push(quote(k) + (gap ? ": " : ":") + v);
741 | }
742 | }
743 | }
744 | } else {
745 |
746 | // Otherwise, iterate through all of the keys in the object.
747 |
748 | Object.keys(value).forEach(function (k) {
749 | var v = str(k, value);
750 | if (v) {
751 | partial.push(quote(k) + (gap ? ": " : ":") + v);
752 | }
753 | });
754 | }
755 |
756 | // Join all of the member texts together, separated with commas,
757 | // and wrap them in braces.
758 |
759 | v = partial.length === 0
760 | ? "{}"
761 | : gap
762 | ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}"
763 | : "{" + partial.join(",") + "}";
764 | gap = mind;
765 | return v;
766 | }
767 | }
768 |
769 | // If the JSON object does not yet have a stringify method, give it one.
770 |
771 | if (typeof JSON.stringify !== "function") {
772 | JSON.stringify = function (value, replacer, space) {
773 |
774 | // The stringify method takes a value and an optional replacer, and an optional
775 | // space parameter, and returns a JSON text. The replacer can be a function
776 | // that can replace values, or an array of strings that will select the keys.
777 | // A default replacer method can be provided. Use of the space parameter can
778 | // produce text that is more easily readable.
779 |
780 | var i;
781 | gap = "";
782 | indent = "";
783 |
784 | // If the space parameter is a number, make an indent string containing that
785 | // many spaces.
786 |
787 | if (typeof space === "number") {
788 | for (i = 0; i < space; i += 1) {
789 | indent += " ";
790 | }
791 |
792 | // If the space parameter is a string, it will be used as the indent string.
793 |
794 | } else if (typeof space === "string") {
795 | indent = space;
796 | }
797 |
798 | // If there is a replacer, it must be a function or an array.
799 | // Otherwise, throw an error.
800 |
801 | rep = replacer;
802 | if (replacer && typeof replacer !== "function" &&
803 | (typeof replacer !== "object" ||
804 | typeof replacer.length !== "number")) {
805 | throw new Error("JSON.stringify");
806 | }
807 |
808 | // Make a fake root object containing our value under the key of ''.
809 | // Return the result of stringifying the value.
810 |
811 | return str("", { "": value });
812 | };
813 | }
814 | }());
815 |
816 |
817 | const parseJson = json_parse();
818 |
819 | function parse(json) {
820 | return parseJson(json);
821 | }
822 |
823 | if (typeof postMessage == "undefined") {
824 | globalThis.parser = { parse };
825 | } else {
826 | addEventListener("message", event => postMessage(parse(event.data)), false);
827 | }
--------------------------------------------------------------------------------
/src/codemirror/css.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.defineMode("css", function(config, parserConfig) {
15 | var inline = parserConfig.inline
16 | if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
17 |
18 | var indentUnit = config.indentUnit,
19 | tokenHooks = parserConfig.tokenHooks,
20 | documentTypes = parserConfig.documentTypes || {},
21 | mediaTypes = parserConfig.mediaTypes || {},
22 | mediaFeatures = parserConfig.mediaFeatures || {},
23 | mediaValueKeywords = parserConfig.mediaValueKeywords || {},
24 | propertyKeywords = parserConfig.propertyKeywords || {},
25 | nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
26 | fontProperties = parserConfig.fontProperties || {},
27 | counterDescriptors = parserConfig.counterDescriptors || {},
28 | colorKeywords = parserConfig.colorKeywords || {},
29 | valueKeywords = parserConfig.valueKeywords || {},
30 | allowNested = parserConfig.allowNested,
31 | lineComment = parserConfig.lineComment,
32 | supportsAtComponent = parserConfig.supportsAtComponent === true,
33 | highlightNonStandardPropertyKeywords = config.highlightNonStandardPropertyKeywords !== false;
34 |
35 | var type, override;
36 | function ret(style, tp) { type = tp; return style; }
37 |
38 | // Tokenizers
39 |
40 | function tokenBase(stream, state) {
41 | var ch = stream.next();
42 | if (tokenHooks[ch]) {
43 | var result = tokenHooks[ch](stream, state);
44 | if (result !== false) return result;
45 | }
46 | if (ch == "@") {
47 | stream.eatWhile(/[\w\\\-]/);
48 | return ret("def", stream.current());
49 | } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
50 | return ret(null, "compare");
51 | } else if (ch == "\"" || ch == "'") {
52 | state.tokenize = tokenString(ch);
53 | return state.tokenize(stream, state);
54 | } else if (ch == "#") {
55 | stream.eatWhile(/[\w\\\-]/);
56 | return ret("atom", "hash");
57 | } else if (ch == "!") {
58 | stream.match(/^\s*\w*/);
59 | return ret("keyword", "important");
60 | } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
61 | stream.eatWhile(/[\w.%]/);
62 | return ret("number", "unit");
63 | } else if (ch === "-") {
64 | if (/[\d.]/.test(stream.peek())) {
65 | stream.eatWhile(/[\w.%]/);
66 | return ret("number", "unit");
67 | } else if (stream.match(/^-[\w\\\-]*/)) {
68 | stream.eatWhile(/[\w\\\-]/);
69 | if (stream.match(/^\s*:/, false))
70 | return ret("variable-2", "variable-definition");
71 | return ret("variable-2", "variable");
72 | } else if (stream.match(/^\w+-/)) {
73 | return ret("meta", "meta");
74 | }
75 | } else if (/[,+>*\/]/.test(ch)) {
76 | return ret(null, "select-op");
77 | } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
78 | return ret("qualifier", "qualifier");
79 | } else if (/[:;{}\[\]\(\)]/.test(ch)) {
80 | return ret(null, ch);
81 | } else if (stream.match(/^[\w-.]+(?=\()/)) {
82 | if (/^(url(-prefix)?|domain|regexp)$/i.test(stream.current())) {
83 | state.tokenize = tokenParenthesized;
84 | }
85 | return ret("variable callee", "variable");
86 | } else if (/[\w\\\-]/.test(ch)) {
87 | stream.eatWhile(/[\w\\\-]/);
88 | return ret("property", "word");
89 | } else {
90 | return ret(null, null);
91 | }
92 | }
93 |
94 | function tokenString(quote) {
95 | return function(stream, state) {
96 | var escaped = false, ch;
97 | while ((ch = stream.next()) != null) {
98 | if (ch == quote && !escaped) {
99 | if (quote == ")") stream.backUp(1);
100 | break;
101 | }
102 | escaped = !escaped && ch == "\\";
103 | }
104 | if (ch == quote || !escaped && quote != ")") state.tokenize = null;
105 | return ret("string", "string");
106 | };
107 | }
108 |
109 | function tokenParenthesized(stream, state) {
110 | stream.next(); // Must be '('
111 | if (!stream.match(/^\s*[\"\')]/, false))
112 | state.tokenize = tokenString(")");
113 | else
114 | state.tokenize = null;
115 | return ret(null, "(");
116 | }
117 |
118 | // Context management
119 |
120 | function Context(type, indent, prev) {
121 | this.type = type;
122 | this.indent = indent;
123 | this.prev = prev;
124 | }
125 |
126 | function pushContext(state, stream, type, indent) {
127 | state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context);
128 | return type;
129 | }
130 |
131 | function popContext(state) {
132 | if (state.context.prev)
133 | state.context = state.context.prev;
134 | return state.context.type;
135 | }
136 |
137 | function pass(type, stream, state) {
138 | return states[state.context.type](type, stream, state);
139 | }
140 | function popAndPass(type, stream, state, n) {
141 | for (var i = n || 1; i > 0; i--)
142 | state.context = state.context.prev;
143 | return pass(type, stream, state);
144 | }
145 |
146 | // Parser
147 |
148 | function wordAsValue(stream) {
149 | var word = stream.current().toLowerCase();
150 | if (valueKeywords.hasOwnProperty(word))
151 | override = "atom";
152 | else if (colorKeywords.hasOwnProperty(word))
153 | override = "keyword";
154 | else
155 | override = "variable";
156 | }
157 |
158 | var states = {};
159 |
160 | states.top = function(type, stream, state) {
161 | if (type == "{") {
162 | return pushContext(state, stream, "block");
163 | } else if (type == "}" && state.context.prev) {
164 | return popContext(state);
165 | } else if (supportsAtComponent && /@component/i.test(type)) {
166 | return pushContext(state, stream, "atComponentBlock");
167 | } else if (/^@(-moz-)?document$/i.test(type)) {
168 | return pushContext(state, stream, "documentTypes");
169 | } else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) {
170 | return pushContext(state, stream, "atBlock");
171 | } else if (/^@(font-face|counter-style)/i.test(type)) {
172 | state.stateArg = type;
173 | return "restricted_atBlock_before";
174 | } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) {
175 | return "keyframes";
176 | } else if (type && type.charAt(0) == "@") {
177 | return pushContext(state, stream, "at");
178 | } else if (type == "hash") {
179 | override = "builtin";
180 | } else if (type == "word") {
181 | override = "tag";
182 | } else if (type == "variable-definition") {
183 | return "maybeprop";
184 | } else if (type == "interpolation") {
185 | return pushContext(state, stream, "interpolation");
186 | } else if (type == ":") {
187 | return "pseudo";
188 | } else if (allowNested && type == "(") {
189 | return pushContext(state, stream, "parens");
190 | }
191 | return state.context.type;
192 | };
193 |
194 | states.block = function(type, stream, state) {
195 | if (type == "word") {
196 | var word = stream.current().toLowerCase();
197 | if (propertyKeywords.hasOwnProperty(word)) {
198 | override = "property";
199 | return "maybeprop";
200 | } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
201 | override = highlightNonStandardPropertyKeywords ? "string-2" : "property";
202 | return "maybeprop";
203 | } else if (allowNested) {
204 | override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
205 | return "block";
206 | } else {
207 | override += " error";
208 | return "maybeprop";
209 | }
210 | } else if (type == "meta") {
211 | return "block";
212 | } else if (!allowNested && (type == "hash" || type == "qualifier")) {
213 | override = "error";
214 | return "block";
215 | } else {
216 | return states.top(type, stream, state);
217 | }
218 | };
219 |
220 | states.maybeprop = function(type, stream, state) {
221 | if (type == ":") return pushContext(state, stream, "prop");
222 | return pass(type, stream, state);
223 | };
224 |
225 | states.prop = function(type, stream, state) {
226 | if (type == ";") return popContext(state);
227 | if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
228 | if (type == "}" || type == "{") return popAndPass(type, stream, state);
229 | if (type == "(") return pushContext(state, stream, "parens");
230 |
231 | if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) {
232 | override += " error";
233 | } else if (type == "word") {
234 | wordAsValue(stream);
235 | } else if (type == "interpolation") {
236 | return pushContext(state, stream, "interpolation");
237 | }
238 | return "prop";
239 | };
240 |
241 | states.propBlock = function(type, _stream, state) {
242 | if (type == "}") return popContext(state);
243 | if (type == "word") { override = "property"; return "maybeprop"; }
244 | return state.context.type;
245 | };
246 |
247 | states.parens = function(type, stream, state) {
248 | if (type == "{" || type == "}") return popAndPass(type, stream, state);
249 | if (type == ")") return popContext(state);
250 | if (type == "(") return pushContext(state, stream, "parens");
251 | if (type == "interpolation") return pushContext(state, stream, "interpolation");
252 | if (type == "word") wordAsValue(stream);
253 | return "parens";
254 | };
255 |
256 | states.pseudo = function(type, stream, state) {
257 | if (type == "meta") return "pseudo";
258 |
259 | if (type == "word") {
260 | override = "variable-3";
261 | return state.context.type;
262 | }
263 | return pass(type, stream, state);
264 | };
265 |
266 | states.documentTypes = function(type, stream, state) {
267 | if (type == "word" && documentTypes.hasOwnProperty(stream.current())) {
268 | override = "tag";
269 | return state.context.type;
270 | } else {
271 | return states.atBlock(type, stream, state);
272 | }
273 | };
274 |
275 | states.atBlock = function(type, stream, state) {
276 | if (type == "(") return pushContext(state, stream, "atBlock_parens");
277 | if (type == "}" || type == ";") return popAndPass(type, stream, state);
278 | if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
279 |
280 | if (type == "interpolation") return pushContext(state, stream, "interpolation");
281 |
282 | if (type == "word") {
283 | var word = stream.current().toLowerCase();
284 | if (word == "only" || word == "not" || word == "and" || word == "or")
285 | override = "keyword";
286 | else if (mediaTypes.hasOwnProperty(word))
287 | override = "attribute";
288 | else if (mediaFeatures.hasOwnProperty(word))
289 | override = "property";
290 | else if (mediaValueKeywords.hasOwnProperty(word))
291 | override = "keyword";
292 | else if (propertyKeywords.hasOwnProperty(word))
293 | override = "property";
294 | else if (nonStandardPropertyKeywords.hasOwnProperty(word))
295 | override = highlightNonStandardPropertyKeywords ? "string-2" : "property";
296 | else if (valueKeywords.hasOwnProperty(word))
297 | override = "atom";
298 | else if (colorKeywords.hasOwnProperty(word))
299 | override = "keyword";
300 | else
301 | override = "error";
302 | }
303 | return state.context.type;
304 | };
305 |
306 | states.atComponentBlock = function(type, stream, state) {
307 | if (type == "}")
308 | return popAndPass(type, stream, state);
309 | if (type == "{")
310 | return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false);
311 | if (type == "word")
312 | override = "error";
313 | return state.context.type;
314 | };
315 |
316 | states.atBlock_parens = function(type, stream, state) {
317 | if (type == ")") return popContext(state);
318 | if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
319 | return states.atBlock(type, stream, state);
320 | };
321 |
322 | states.restricted_atBlock_before = function(type, stream, state) {
323 | if (type == "{")
324 | return pushContext(state, stream, "restricted_atBlock");
325 | if (type == "word" && state.stateArg == "@counter-style") {
326 | override = "variable";
327 | return "restricted_atBlock_before";
328 | }
329 | return pass(type, stream, state);
330 | };
331 |
332 | states.restricted_atBlock = function(type, stream, state) {
333 | if (type == "}") {
334 | state.stateArg = null;
335 | return popContext(state);
336 | }
337 | if (type == "word") {
338 | if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||
339 | (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))
340 | override = "error";
341 | else
342 | override = "property";
343 | return "maybeprop";
344 | }
345 | return "restricted_atBlock";
346 | };
347 |
348 | states.keyframes = function(type, stream, state) {
349 | if (type == "word") { override = "variable"; return "keyframes"; }
350 | if (type == "{") return pushContext(state, stream, "top");
351 | return pass(type, stream, state);
352 | };
353 |
354 | states.at = function(type, stream, state) {
355 | if (type == ";") return popContext(state);
356 | if (type == "{" || type == "}") return popAndPass(type, stream, state);
357 | if (type == "word") override = "tag";
358 | else if (type == "hash") override = "builtin";
359 | return "at";
360 | };
361 |
362 | states.interpolation = function(type, stream, state) {
363 | if (type == "}") return popContext(state);
364 | if (type == "{" || type == ";") return popAndPass(type, stream, state);
365 | if (type == "word") override = "variable";
366 | else if (type != "variable" && type != "(" && type != ")") override = "error";
367 | return "interpolation";
368 | };
369 |
370 | return {
371 | startState: function(base) {
372 | return {tokenize: null,
373 | state: inline ? "block" : "top",
374 | stateArg: null,
375 | context: new Context(inline ? "block" : "top", base || 0, null)};
376 | },
377 |
378 | token: function(stream, state) {
379 | if (!state.tokenize && stream.eatSpace()) return null;
380 | var style = (state.tokenize || tokenBase)(stream, state);
381 | if (style && typeof style == "object") {
382 | type = style[1];
383 | style = style[0];
384 | }
385 | override = style;
386 | if (type != "comment")
387 | state.state = states[state.state](type, stream, state);
388 | return override;
389 | },
390 |
391 | indent: function(state, textAfter) {
392 | var cx = state.context, ch = textAfter && textAfter.charAt(0);
393 | var indent = cx.indent;
394 | if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
395 | if (cx.prev) {
396 | if (ch == "}" && (cx.type == "block" || cx.type == "top" ||
397 | cx.type == "interpolation" || cx.type == "restricted_atBlock")) {
398 | // Resume indentation from parent context.
399 | cx = cx.prev;
400 | indent = cx.indent;
401 | } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
402 | ch == "{" && (cx.type == "at" || cx.type == "atBlock")) {
403 | // Dedent relative to current context.
404 | indent = Math.max(0, cx.indent - indentUnit);
405 | }
406 | }
407 | return indent;
408 | },
409 |
410 | electricChars: "}",
411 | blockCommentStart: "/*",
412 | blockCommentEnd: "*/",
413 | blockCommentContinue: " * ",
414 | lineComment: lineComment,
415 | fold: "brace"
416 | };
417 | });
418 |
419 | function keySet(array) {
420 | var keys = {};
421 | for (var i = 0; i < array.length; ++i) {
422 | keys[array[i].toLowerCase()] = true;
423 | }
424 | return keys;
425 | }
426 |
427 | var documentTypes_ = [
428 | "domain", "regexp", "url", "url-prefix"
429 | ], documentTypes = keySet(documentTypes_);
430 |
431 | var mediaTypes_ = [
432 | "all", "aural", "braille", "handheld", "print", "projection", "screen",
433 | "tty", "tv", "embossed"
434 | ], mediaTypes = keySet(mediaTypes_);
435 |
436 | var mediaFeatures_ = [
437 | "width", "min-width", "max-width", "height", "min-height", "max-height",
438 | "device-width", "min-device-width", "max-device-width", "device-height",
439 | "min-device-height", "max-device-height", "aspect-ratio",
440 | "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
441 | "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
442 | "max-color", "color-index", "min-color-index", "max-color-index",
443 | "monochrome", "min-monochrome", "max-monochrome", "resolution",
444 | "min-resolution", "max-resolution", "scan", "grid", "orientation",
445 | "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio",
446 | "pointer", "any-pointer", "hover", "any-hover", "prefers-color-scheme",
447 | "dynamic-range", "video-dynamic-range"
448 | ], mediaFeatures = keySet(mediaFeatures_);
449 |
450 | var mediaValueKeywords_ = [
451 | "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover",
452 | "interlace", "progressive",
453 | "dark", "light",
454 | "standard", "high"
455 | ], mediaValueKeywords = keySet(mediaValueKeywords_);
456 |
457 | var propertyKeywords_ = [
458 | "align-content", "align-items", "align-self", "alignment-adjust",
459 | "alignment-baseline", "all", "anchor-point", "animation", "animation-delay",
460 | "animation-direction", "animation-duration", "animation-fill-mode",
461 | "animation-iteration-count", "animation-name", "animation-play-state",
462 | "animation-timing-function", "appearance", "azimuth", "backdrop-filter",
463 | "backface-visibility", "background", "background-attachment",
464 | "background-blend-mode", "background-clip", "background-color",
465 | "background-image", "background-origin", "background-position",
466 | "background-position-x", "background-position-y", "background-repeat",
467 | "background-size", "baseline-shift", "binding", "bleed", "block-size",
468 | "bookmark-label", "bookmark-level", "bookmark-state", "bookmark-target",
469 | "border", "border-bottom", "border-bottom-color", "border-bottom-left-radius",
470 | "border-bottom-right-radius", "border-bottom-style", "border-bottom-width",
471 | "border-collapse", "border-color", "border-image", "border-image-outset",
472 | "border-image-repeat", "border-image-slice", "border-image-source",
473 | "border-image-width", "border-left", "border-left-color", "border-left-style",
474 | "border-left-width", "border-radius", "border-right", "border-right-color",
475 | "border-right-style", "border-right-width", "border-spacing", "border-style",
476 | "border-top", "border-top-color", "border-top-left-radius",
477 | "border-top-right-radius", "border-top-style", "border-top-width",
478 | "border-width", "bottom", "box-decoration-break", "box-shadow", "box-sizing",
479 | "break-after", "break-before", "break-inside", "caption-side", "caret-color",
480 | "clear", "clip", "color", "color-profile", "column-count", "column-fill",
481 | "column-gap", "column-rule", "column-rule-color", "column-rule-style",
482 | "column-rule-width", "column-span", "column-width", "columns", "contain",
483 | "content", "counter-increment", "counter-reset", "crop", "cue", "cue-after",
484 | "cue-before", "cursor", "direction", "display", "dominant-baseline",
485 | "drop-initial-after-adjust", "drop-initial-after-align",
486 | "drop-initial-before-adjust", "drop-initial-before-align", "drop-initial-size",
487 | "drop-initial-value", "elevation", "empty-cells", "fit", "fit-content", "fit-position",
488 | "flex", "flex-basis", "flex-direction", "flex-flow", "flex-grow",
489 | "flex-shrink", "flex-wrap", "float", "float-offset", "flow-from", "flow-into",
490 | "font", "font-family", "font-feature-settings", "font-kerning",
491 | "font-language-override", "font-optical-sizing", "font-size",
492 | "font-size-adjust", "font-stretch", "font-style", "font-synthesis",
493 | "font-variant", "font-variant-alternates", "font-variant-caps",
494 | "font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric",
495 | "font-variant-position", "font-variation-settings", "font-weight", "gap",
496 | "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", "grid-auto-rows",
497 | "grid-column", "grid-column-end", "grid-column-gap", "grid-column-start",
498 | "grid-gap", "grid-row", "grid-row-end", "grid-row-gap", "grid-row-start",
499 | "grid-template", "grid-template-areas", "grid-template-columns",
500 | "grid-template-rows", "hanging-punctuation", "height", "hyphens", "icon",
501 | "image-orientation", "image-rendering", "image-resolution", "inline-box-align",
502 | "inset", "inset-block", "inset-block-end", "inset-block-start", "inset-inline",
503 | "inset-inline-end", "inset-inline-start", "isolation", "justify-content",
504 | "justify-items", "justify-self", "left", "letter-spacing", "line-break",
505 | "line-height", "line-height-step", "line-stacking", "line-stacking-ruby",
506 | "line-stacking-shift", "line-stacking-strategy", "list-style",
507 | "list-style-image", "list-style-position", "list-style-type", "margin",
508 | "margin-bottom", "margin-left", "margin-right", "margin-top", "marks",
509 | "marquee-direction", "marquee-loop", "marquee-play-count", "marquee-speed",
510 | "marquee-style", "mask-clip", "mask-composite", "mask-image", "mask-mode",
511 | "mask-origin", "mask-position", "mask-repeat", "mask-size","mask-type",
512 | "max-block-size", "max-height", "max-inline-size",
513 | "max-width", "min-block-size", "min-height", "min-inline-size", "min-width",
514 | "mix-blend-mode", "move-to", "nav-down", "nav-index", "nav-left", "nav-right",
515 | "nav-up", "object-fit", "object-position", "offset", "offset-anchor",
516 | "offset-distance", "offset-path", "offset-position", "offset-rotate",
517 | "opacity", "order", "orphans", "outline", "outline-color", "outline-offset",
518 | "outline-style", "outline-width", "overflow", "overflow-style",
519 | "overflow-wrap", "overflow-x", "overflow-y", "padding", "padding-bottom",
520 | "padding-left", "padding-right", "padding-top", "page", "page-break-after",
521 | "page-break-before", "page-break-inside", "page-policy", "pause",
522 | "pause-after", "pause-before", "perspective", "perspective-origin", "pitch",
523 | "pitch-range", "place-content", "place-items", "place-self", "play-during",
524 | "position", "presentation-level", "punctuation-trim", "quotes",
525 | "region-break-after", "region-break-before", "region-break-inside",
526 | "region-fragment", "rendering-intent", "resize", "rest", "rest-after",
527 | "rest-before", "richness", "right", "rotate", "rotation", "rotation-point",
528 | "row-gap", "ruby-align", "ruby-overhang", "ruby-position", "ruby-span",
529 | "scale", "scroll-behavior", "scroll-margin", "scroll-margin-block",
530 | "scroll-margin-block-end", "scroll-margin-block-start", "scroll-margin-bottom",
531 | "scroll-margin-inline", "scroll-margin-inline-end",
532 | "scroll-margin-inline-start", "scroll-margin-left", "scroll-margin-right",
533 | "scroll-margin-top", "scroll-padding", "scroll-padding-block",
534 | "scroll-padding-block-end", "scroll-padding-block-start",
535 | "scroll-padding-bottom", "scroll-padding-inline", "scroll-padding-inline-end",
536 | "scroll-padding-inline-start", "scroll-padding-left", "scroll-padding-right",
537 | "scroll-padding-top", "scroll-snap-align", "scroll-snap-type",
538 | "shape-image-threshold", "shape-inside", "shape-margin", "shape-outside",
539 | "size", "speak", "speak-as", "speak-header", "speak-numeral",
540 | "speak-punctuation", "speech-rate", "stress", "string-set", "tab-size",
541 | "table-layout", "target", "target-name", "target-new", "target-position",
542 | "text-align", "text-align-last", "text-combine-upright", "text-decoration",
543 | "text-decoration-color", "text-decoration-line", "text-decoration-skip",
544 | "text-decoration-skip-ink", "text-decoration-style", "text-emphasis",
545 | "text-emphasis-color", "text-emphasis-position", "text-emphasis-style",
546 | "text-height", "text-indent", "text-justify", "text-orientation",
547 | "text-outline", "text-overflow", "text-rendering", "text-shadow",
548 | "text-size-adjust", "text-space-collapse", "text-transform",
549 | "text-underline-position", "text-wrap", "top", "touch-action", "transform", "transform-origin",
550 | "transform-style", "transition", "transition-delay", "transition-duration",
551 | "transition-property", "transition-timing-function", "translate",
552 | "unicode-bidi", "user-select", "vertical-align", "visibility", "voice-balance",
553 | "voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate",
554 | "voice-stress", "voice-volume", "volume", "white-space", "widows", "width",
555 | "will-change", "word-break", "word-spacing", "word-wrap", "writing-mode", "z-index",
556 | // SVG-specific
557 | "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
558 | "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
559 | "color-interpolation", "color-interpolation-filters",
560 | "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
561 | "marker", "marker-end", "marker-mid", "marker-start", "paint-order", "shape-rendering", "stroke",
562 | "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
563 | "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
564 | "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
565 | "glyph-orientation-vertical", "text-anchor", "writing-mode",
566 | ], propertyKeywords = keySet(propertyKeywords_);
567 |
568 | var nonStandardPropertyKeywords_ = [
569 | "accent-color", "aspect-ratio", "border-block", "border-block-color", "border-block-end",
570 | "border-block-end-color", "border-block-end-style", "border-block-end-width",
571 | "border-block-start", "border-block-start-color", "border-block-start-style",
572 | "border-block-start-width", "border-block-style", "border-block-width",
573 | "border-inline", "border-inline-color", "border-inline-end",
574 | "border-inline-end-color", "border-inline-end-style",
575 | "border-inline-end-width", "border-inline-start", "border-inline-start-color",
576 | "border-inline-start-style", "border-inline-start-width",
577 | "border-inline-style", "border-inline-width", "content-visibility", "margin-block",
578 | "margin-block-end", "margin-block-start", "margin-inline", "margin-inline-end",
579 | "margin-inline-start", "overflow-anchor", "overscroll-behavior", "padding-block", "padding-block-end",
580 | "padding-block-start", "padding-inline", "padding-inline-end",
581 | "padding-inline-start", "scroll-snap-stop", "scrollbar-3d-light-color",
582 | "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
583 | "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
584 | "scrollbar-track-color", "searchfield-cancel-button", "searchfield-decoration",
585 | "searchfield-results-button", "searchfield-results-decoration", "shape-inside", "zoom"
586 | ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
587 |
588 | var fontProperties_ = [
589 | "font-display", "font-family", "src", "unicode-range", "font-variant",
590 | "font-feature-settings", "font-stretch", "font-weight", "font-style"
591 | ], fontProperties = keySet(fontProperties_);
592 |
593 | var counterDescriptors_ = [
594 | "additive-symbols", "fallback", "negative", "pad", "prefix", "range",
595 | "speak-as", "suffix", "symbols", "system"
596 | ], counterDescriptors = keySet(counterDescriptors_);
597 |
598 | var colorKeywords_ = [
599 | "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
600 | "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
601 | "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
602 | "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
603 | "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen",
604 | "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
605 | "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet",
606 | "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick",
607 | "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
608 | "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
609 | "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
610 | "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
611 | "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink",
612 | "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey",
613 | "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
614 | "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
615 | "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
616 | "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
617 | "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
618 | "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
619 | "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
620 | "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
621 | "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
622 | "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan",
623 | "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
624 | "whitesmoke", "yellow", "yellowgreen"
625 | ], colorKeywords = keySet(colorKeywords_);
626 |
627 | var valueKeywords_ = [
628 | "above", "absolute", "activeborder", "additive", "activecaption", "afar",
629 | "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
630 | "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
631 | "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
632 | "avoid-region", "axis-pan", "background", "backwards", "baseline", "below", "bidi-override", "binary",
633 | "bengali", "blink", "block", "block-axis", "blur", "bold", "bolder", "border", "border-box",
634 | "both", "bottom", "break", "break-all", "break-word", "brightness", "bullets", "button", "button-bevel",
635 | "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
636 | "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
637 | "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
638 | "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
639 | "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
640 | "compact", "condensed", "contain", "content", "contents",
641 | "content-box", "context-menu", "continuous", "contrast", "copy", "counter", "counters", "cover", "crop",
642 | "cross", "crosshair", "cubic-bezier", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
643 | "decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
644 | "destination-in", "destination-out", "destination-over", "devanagari", "difference",
645 | "disc", "discard", "disclosure-closed", "disclosure-open", "document",
646 | "dot-dash", "dot-dot-dash",
647 | "dotted", "double", "down", "drop-shadow", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
648 | "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
649 | "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
650 | "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
651 | "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
652 | "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
653 | "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
654 | "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
655 | "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
656 | "extra-expanded", "fantasy", "fast", "fill", "fill-box", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
657 | "forwards", "from", "geometricPrecision", "georgian", "grayscale", "graytext", "grid", "groove",
658 | "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
659 | "help", "hidden", "hide", "higher", "highlight", "highlighttext",
660 | "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "hue-rotate", "icon", "ignore",
661 | "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
662 | "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
663 | "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert",
664 | "italic", "japanese-formal", "japanese-informal", "justify", "kannada",
665 | "katakana", "katakana-iroha", "keep-all", "khmer",
666 | "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
667 | "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten",
668 | "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
669 | "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
670 | "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
671 | "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "manipulation", "match", "matrix", "matrix3d",
672 | "media-controls-background", "media-current-time-display",
673 | "media-fullscreen-button", "media-mute-button", "media-play-button",
674 | "media-return-to-realtime-button", "media-rewind-button",
675 | "media-seek-back-button", "media-seek-forward-button", "media-slider",
676 | "media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
677 | "media-volume-slider-container", "media-volume-sliderthumb", "medium",
678 | "menu", "menulist", "menulist-button", "menulist-text",
679 | "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
680 | "mix", "mongolian", "monospace", "move", "multiple", "multiple_mask_images", "multiply", "myanmar", "n-resize",
681 | "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
682 | "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
683 | "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
684 | "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
685 | "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
686 | "painted", "page", "paused", "persian", "perspective", "pinch-zoom", "plus-darker", "plus-lighter",
687 | "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
688 | "progress", "push-button", "radial-gradient", "radio", "read-only",
689 | "read-write", "read-write-plaintext-only", "rectangle", "region",
690 | "relative", "repeat", "repeating-linear-gradient",
691 | "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse",
692 | "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
693 | "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
694 | "s-resize", "sans-serif", "saturate", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
695 | "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
696 | "searchfield-cancel-button", "searchfield-decoration",
697 | "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end",
698 | "semi-condensed", "semi-expanded", "separate", "sepia", "serif", "show", "sidama",
699 | "simp-chinese-formal", "simp-chinese-informal", "single",
700 | "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
701 | "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
702 | "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
703 | "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
704 | "square-button", "start", "static", "status-bar", "stretch", "stroke", "stroke-box", "sub",
705 | "subpixel-antialiased", "svg_masks", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
706 | "table-caption", "table-cell", "table-column", "table-column-group",
707 | "table-footer-group", "table-header-group", "table-row", "table-row-group",
708 | "tamil",
709 | "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
710 | "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
711 | "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
712 | "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
713 | "trad-chinese-formal", "trad-chinese-informal", "transform",
714 | "translate", "translate3d", "translateX", "translateY", "translateZ",
715 | "transparent", "ultra-condensed", "ultra-expanded", "underline", "unidirectional-pan", "unset", "up",
716 | "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
717 | "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
718 | "var", "vertical", "vertical-text", "view-box", "visible", "visibleFill", "visiblePainted",
719 | "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
720 | "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor",
721 | "xx-large", "xx-small"
722 | ], valueKeywords = keySet(valueKeywords_);
723 |
724 | var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_)
725 | .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_)
726 | .concat(valueKeywords_);
727 | CodeMirror.registerHelper("hintWords", "css", allWords);
728 |
729 | function tokenCComment(stream, state) {
730 | var maybeEnd = false, ch;
731 | while ((ch = stream.next()) != null) {
732 | if (maybeEnd && ch == "/") {
733 | state.tokenize = null;
734 | break;
735 | }
736 | maybeEnd = (ch == "*");
737 | }
738 | return ["comment", "comment"];
739 | }
740 |
741 | CodeMirror.defineMIME("text/css", {
742 | documentTypes: documentTypes,
743 | mediaTypes: mediaTypes,
744 | mediaFeatures: mediaFeatures,
745 | mediaValueKeywords: mediaValueKeywords,
746 | propertyKeywords: propertyKeywords,
747 | nonStandardPropertyKeywords: nonStandardPropertyKeywords,
748 | fontProperties: fontProperties,
749 | counterDescriptors: counterDescriptors,
750 | colorKeywords: colorKeywords,
751 | valueKeywords: valueKeywords,
752 | tokenHooks: {
753 | "/": function(stream, state) {
754 | if (!stream.eat("*")) return false;
755 | state.tokenize = tokenCComment;
756 | return tokenCComment(stream, state);
757 | }
758 | },
759 | name: "css"
760 | });
761 |
762 | CodeMirror.defineMIME("text/x-scss", {
763 | mediaTypes: mediaTypes,
764 | mediaFeatures: mediaFeatures,
765 | mediaValueKeywords: mediaValueKeywords,
766 | propertyKeywords: propertyKeywords,
767 | nonStandardPropertyKeywords: nonStandardPropertyKeywords,
768 | colorKeywords: colorKeywords,
769 | valueKeywords: valueKeywords,
770 | fontProperties: fontProperties,
771 | allowNested: true,
772 | lineComment: "//",
773 | tokenHooks: {
774 | "/": function(stream, state) {
775 | if (stream.eat("/")) {
776 | stream.skipToEnd();
777 | return ["comment", "comment"];
778 | } else if (stream.eat("*")) {
779 | state.tokenize = tokenCComment;
780 | return tokenCComment(stream, state);
781 | } else {
782 | return ["operator", "operator"];
783 | }
784 | },
785 | ":": function(stream) {
786 | if (stream.match(/^\s*\{/, false))
787 | return [null, null]
788 | return false;
789 | },
790 | "$": function(stream) {
791 | stream.match(/^[\w-]+/);
792 | if (stream.match(/^\s*:/, false))
793 | return ["variable-2", "variable-definition"];
794 | return ["variable-2", "variable"];
795 | },
796 | "#": function(stream) {
797 | if (!stream.eat("{")) return false;
798 | return [null, "interpolation"];
799 | }
800 | },
801 | name: "css",
802 | helperType: "scss"
803 | });
804 |
805 | CodeMirror.defineMIME("text/x-less", {
806 | mediaTypes: mediaTypes,
807 | mediaFeatures: mediaFeatures,
808 | mediaValueKeywords: mediaValueKeywords,
809 | propertyKeywords: propertyKeywords,
810 | nonStandardPropertyKeywords: nonStandardPropertyKeywords,
811 | colorKeywords: colorKeywords,
812 | valueKeywords: valueKeywords,
813 | fontProperties: fontProperties,
814 | allowNested: true,
815 | lineComment: "//",
816 | tokenHooks: {
817 | "/": function(stream, state) {
818 | if (stream.eat("/")) {
819 | stream.skipToEnd();
820 | return ["comment", "comment"];
821 | } else if (stream.eat("*")) {
822 | state.tokenize = tokenCComment;
823 | return tokenCComment(stream, state);
824 | } else {
825 | return ["operator", "operator"];
826 | }
827 | },
828 | "@": function(stream) {
829 | if (stream.eat("{")) return [null, "interpolation"];
830 | if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false;
831 | stream.eatWhile(/[\w\\\-]/);
832 | if (stream.match(/^\s*:/, false))
833 | return ["variable-2", "variable-definition"];
834 | return ["variable-2", "variable"];
835 | },
836 | "&": function() {
837 | return ["atom", "atom"];
838 | }
839 | },
840 | name: "css",
841 | helperType: "less"
842 | });
843 |
844 | CodeMirror.defineMIME("text/x-gss", {
845 | documentTypes: documentTypes,
846 | mediaTypes: mediaTypes,
847 | mediaFeatures: mediaFeatures,
848 | propertyKeywords: propertyKeywords,
849 | nonStandardPropertyKeywords: nonStandardPropertyKeywords,
850 | fontProperties: fontProperties,
851 | counterDescriptors: counterDescriptors,
852 | colorKeywords: colorKeywords,
853 | valueKeywords: valueKeywords,
854 | supportsAtComponent: true,
855 | tokenHooks: {
856 | "/": function(stream, state) {
857 | if (!stream.eat("*")) return false;
858 | state.tokenize = tokenCComment;
859 | return tokenCComment(stream, state);
860 | }
861 | },
862 | name: "css",
863 | helperType: "gss"
864 | });
865 |
866 | });
867 |
--------------------------------------------------------------------------------
/src/js/content.js:
--------------------------------------------------------------------------------
1 | /* global window, document, chrome, top, BigInt */
2 |
3 | const CLASS_COLLAPSED = "collapsed";
4 | const CLASS_HOVERED = "hovered";
5 | const CLASS_SELECTED = "selected";
6 | const TAG_LIST_ITEM = "LI";
7 | const TITLE_OPEN_COLLAPSIBLES = "expand all";
8 | const LABEL_OPEN_COLLAPSIBLES = "+";
9 | const TITLE_CLOSE_COLLAPSIBLES = "collapse all";
10 | const LABEL_CLOSE_COLLAPSIBLES = "-";
11 | const TITLE_VIEW_SOURCE = "view unformatted source";
12 | const LABEL_VIEW_SOURCE = "view source";
13 | const MENU_ID_COPY_PATH = "copy-path";
14 | const MENU_ID_COPY_VALUE = "copy-value";
15 | const MENU_ID_COPY_JSON_VALUE = "copy-json-value";
16 | // cf. https://github.com/mathiasbynens/mothereff.in/blob/master/js-variables/eff.js
17 | // eslint-disable-next-line no-misleading-character-class
18 | const REGEXP_IDENTIFIER = /^(?:[$A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D])(?:[$0-9A-Z_a-z\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF])*$/;
19 |
20 | // regexpxs extracted from
21 | // (c) BSD-3-Clause
22 | // https://github.com/fastify/secure-json-parse/graphs/contributors and https://github.com/hapijs/bourne/graphs/contributors
23 |
24 | const suspectProtoRx = /(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])/;
25 | const suspectConstructorRx = /(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)/;
26 |
27 | /*
28 | json_parse.js
29 | 2012-06-20
30 |
31 | Public Domain.
32 |
33 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
34 |
35 | This file creates a json_parse function.
36 | During create you can (optionally) specify some behavioural switches
37 |
38 | require('json-bigint')(options)
39 |
40 | The optional options parameter holds switches that drive certain
41 | aspects of the parsing process:
42 | * options.strict = true will warn about duplicate-key usage in the json.
43 | The default (strict = false) will silently ignore those and overwrite
44 | values for keys that are in duplicate use.
45 |
46 | The resulting function follows this signature:
47 | json_parse(text, reviver)
48 | This method parses a JSON text to produce an object or array.
49 | It can throw a SyntaxError exception.
50 |
51 | The optional reviver parameter is a function that can filter and
52 | transform the results. It receives each of the keys and values,
53 | and its return value is used instead of the original value.
54 | If it returns what it received, then the structure is not modified.
55 | If it returns undefined then the member is deleted.
56 |
57 | Example:
58 |
59 | // Parse the text. Values that look like ISO date strings will
60 | // be converted to Date objects.
61 |
62 | myData = json_parse(text, function (key, value) {
63 | var a;
64 | if (typeof value === 'string') {
65 | a =
66 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
67 | if (a) {
68 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
69 | +a[5], +a[6]));
70 | }
71 | }
72 | return value;
73 | });
74 |
75 | This is a reference implementation. You are free to copy, modify, or
76 | redistribute.
77 |
78 | This code should be minified before deployment.
79 | See http://javascript.crockford.com/jsmin.html
80 |
81 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
82 | NOT CONTROL.
83 | */
84 |
85 | /*members "", "\"", "\/", "\\", at, b, call, charAt, f, fromCharCode,
86 | hasOwnProperty, message, n, name, prototype, push, r, t, text
87 | */
88 |
89 | var json_parse = function (options) {
90 | "use strict";
91 |
92 | // This is a function that can parse a JSON text, producing a JavaScript
93 | // data structure. It is a simple, recursive descent parser. It does not use
94 | // eval or regular expressions, so it can be used as a model for implementing
95 | // a JSON parser in other languages.
96 |
97 | // We are defining the function inside of another function to avoid creating
98 | // global variables.
99 |
100 | // Default options one can override by passing options to the parse()
101 | var _options = {
102 | strict: false, // not being strict means do not generate syntax errors for "duplicate key"
103 | storeAsString: false, // toggles whether the values should be stored as BigNumber (default) or a string
104 | alwaysParseAsBig: false, // toggles whether all numbers should be Big
105 | useNativeBigInt: false, // toggles whether to use native BigInt instead of bignumber.js
106 | protoAction: "error",
107 | constructorAction: "error",
108 | };
109 |
110 | // If there are options, then use them to override the default _options
111 | if (options !== undefined && options !== null) {
112 | if (options.strict === true) {
113 | _options.strict = true;
114 | }
115 | if (options.storeAsString === true) {
116 | _options.storeAsString = true;
117 | }
118 | _options.alwaysParseAsBig =
119 | options.alwaysParseAsBig === true ? options.alwaysParseAsBig : false;
120 | _options.useNativeBigInt =
121 | options.useNativeBigInt === true ? options.useNativeBigInt : false;
122 |
123 | if (typeof options.constructorAction !== "undefined") {
124 | if (
125 | options.constructorAction === "error" ||
126 | options.constructorAction === "ignore" ||
127 | options.constructorAction === "preserve"
128 | ) {
129 | _options.constructorAction = options.constructorAction;
130 | } else {
131 | throw new Error(
132 | `Incorrect value for constructorAction option, must be "error", "ignore" or undefined but passed ${options.constructorAction}`
133 | );
134 | }
135 | }
136 |
137 | if (typeof options.protoAction !== "undefined") {
138 | if (
139 | options.protoAction === "error" ||
140 | options.protoAction === "ignore" ||
141 | options.protoAction === "preserve"
142 | ) {
143 | _options.protoAction = options.protoAction;
144 | } else {
145 | throw new Error(
146 | `Incorrect value for protoAction option, must be "error", "ignore" or undefined but passed ${options.protoAction}`
147 | );
148 | }
149 | }
150 | }
151 |
152 | var at, // The index of the current character
153 | ch, // The current character
154 | escapee = {
155 | "\"": "\"",
156 | "\\": "\\",
157 | "/": "/",
158 | b: "\b",
159 | f: "\f",
160 | n: "\n",
161 | r: "\r",
162 | t: "\t",
163 | },
164 | text,
165 | error = function (m) {
166 | // Call error when something is wrong.
167 |
168 | throw {
169 | name: "SyntaxError",
170 | message: m,
171 | at: at,
172 | text: text,
173 | };
174 | },
175 | next = function (c) {
176 | // If a c parameter is provided, verify that it matches the current character.
177 |
178 | if (c && c !== ch) {
179 | error("Expected '" + c + "' instead of '" + ch + "'");
180 | }
181 |
182 | // Get the next character. When there are no more characters,
183 | // return the empty string.
184 |
185 | ch = text.charAt(at);
186 | at += 1;
187 | return ch;
188 | },
189 | number = function () {
190 | // Parse a number value.
191 |
192 | var number,
193 | string = "";
194 |
195 | if (ch === "-") {
196 | string = "-";
197 | next("-");
198 | }
199 | while (ch >= "0" && ch <= "9") {
200 | string += ch;
201 | next();
202 | }
203 | if (ch === ".") {
204 | string += ".";
205 | while (next() && ch >= "0" && ch <= "9") {
206 | string += ch;
207 | }
208 | }
209 | if (ch === "e" || ch === "E") {
210 | string += ch;
211 | next();
212 | if (ch === "-" || ch === "+") {
213 | string += ch;
214 | next();
215 | }
216 | while (ch >= "0" && ch <= "9") {
217 | string += ch;
218 | next();
219 | }
220 | }
221 | number = +string;
222 | if (!isFinite(number)) {
223 | error("Bad number");
224 | } else {
225 | // if (BigNumber == null) BigNumber = require("bignumber.js");
226 | if (Number.isSafeInteger(number))
227 | return !_options.alwaysParseAsBig
228 | ? number
229 | : BigInt(number);
230 | else
231 | // Number with fractional part should be treated as number(double) including big integers in scientific notation, i.e 1.79e+308
232 | return _options.storeAsString
233 | ? string
234 | : /[.eE]/.test(string)
235 | ? number
236 | : BigInt(string);
237 | }
238 | },
239 | string = function () {
240 | // Parse a string value.
241 |
242 | var hex,
243 | i,
244 | string = "",
245 | uffff;
246 |
247 | // When parsing for string values, we must look for " and \ characters.
248 |
249 | if (ch === "\"") {
250 | var startAt = at;
251 | while (next()) {
252 | if (ch === "\"") {
253 | if (at - 1 > startAt) string += text.substring(startAt, at - 1);
254 | next();
255 | return string;
256 | }
257 | if (ch === "\\") {
258 | if (at - 1 > startAt) string += text.substring(startAt, at - 1);
259 | next();
260 | if (ch === "u") {
261 | uffff = 0;
262 | for (i = 0; i < 4; i += 1) {
263 | hex = parseInt(next(), 16);
264 | if (!isFinite(hex)) {
265 | break;
266 | }
267 | uffff = uffff * 16 + hex;
268 | }
269 | string += String.fromCharCode(uffff);
270 | } else if (typeof escapee[ch] === "string") {
271 | string += escapee[ch];
272 | } else {
273 | break;
274 | }
275 | startAt = at;
276 | }
277 | }
278 | }
279 | error("Bad string");
280 | },
281 | white = function () {
282 | // Skip whitespace.
283 |
284 | while (ch && ch <= " ") {
285 | next();
286 | }
287 | },
288 | word = function () {
289 | // true, false, or null.
290 |
291 | switch (ch) {
292 | case "t":
293 | next("t");
294 | next("r");
295 | next("u");
296 | next("e");
297 | return true;
298 | case "f":
299 | next("f");
300 | next("a");
301 | next("l");
302 | next("s");
303 | next("e");
304 | return false;
305 | case "n":
306 | next("n");
307 | next("u");
308 | next("l");
309 | next("l");
310 | return null;
311 | }
312 | error("Unexpected '" + ch + "'");
313 | },
314 | value, // Place holder for the value function.
315 | array = function () {
316 | // Parse an array value.
317 |
318 | var array = [];
319 |
320 | if (ch === "[") {
321 | next("[");
322 | white();
323 | if (ch === "]") {
324 | next("]");
325 | return array; // empty array
326 | }
327 | while (ch) {
328 | array.push(value());
329 | white();
330 | if (ch === "]") {
331 | next("]");
332 | return array;
333 | }
334 | next(",");
335 | white();
336 | }
337 | }
338 | error("Bad array");
339 | },
340 | object = function () {
341 | // Parse an object value.
342 |
343 | var key,
344 | object = Object.create(null);
345 |
346 | if (ch === "{") {
347 | next("{");
348 | white();
349 | if (ch === "}") {
350 | next("}");
351 | return object; // empty object
352 | }
353 | while (ch) {
354 | key = string();
355 | white();
356 | next(":");
357 | if (
358 | _options.strict === true &&
359 | Object.hasOwnProperty.call(object, key)
360 | ) {
361 | error("Duplicate key \"" + key + "\"");
362 | }
363 |
364 | if (suspectProtoRx.test(key) === true) {
365 | if (_options.protoAction === "error") {
366 | error("Object contains forbidden prototype property");
367 | } else if (_options.protoAction === "ignore") {
368 | value();
369 | } else {
370 | object[key] = value();
371 | }
372 | } else if (suspectConstructorRx.test(key) === true) {
373 | if (_options.constructorAction === "error") {
374 | error("Object contains forbidden constructor property");
375 | } else if (_options.constructorAction === "ignore") {
376 | value();
377 | } else {
378 | object[key] = value();
379 | }
380 | } else {
381 | object[key] = value();
382 | }
383 |
384 | white();
385 | if (ch === "}") {
386 | next("}");
387 | return object;
388 | }
389 | next(",");
390 | white();
391 | }
392 | }
393 | error("Bad object");
394 | };
395 |
396 | value = function () {
397 | // Parse a JSON value. It could be an object, an array, a string, a number,
398 | // or a word.
399 |
400 | white();
401 | switch (ch) {
402 | case "{":
403 | return object();
404 | case "[":
405 | return array();
406 | case "\"":
407 | return string();
408 | case "-":
409 | return number();
410 | default:
411 | return ch >= "0" && ch <= "9" ? number() : word();
412 | }
413 | };
414 |
415 | // Return the json_parse function. It will have access to all of the above
416 | // functions and variables.
417 |
418 | return function (source, reviver) {
419 | var result;
420 |
421 | text = source + "";
422 | at = 0;
423 | ch = " ";
424 | result = value();
425 | white();
426 | if (ch) {
427 | error("Syntax error");
428 | }
429 |
430 | // If there is a reviver function, we recursively walk the new structure,
431 | // passing each name/value pair to the reviver function for possible
432 | // transformation, starting with a temporary root object that holds the result
433 | // in an empty key. If there is not a reviver function, we simply return the
434 | // result.
435 |
436 | return typeof reviver === "function"
437 | ? (function walk(holder, key) {
438 | var v,
439 | value = holder[key];
440 | if (value && typeof value === "object") {
441 | Object.keys(value).forEach(function (k) {
442 | v = walk(value, k);
443 | if (v !== undefined) {
444 | value[k] = v;
445 | } else {
446 | delete value[k];
447 | }
448 | });
449 | }
450 | return reviver.call(holder, key, value);
451 | })({ "": result }, "")
452 | : result;
453 | };
454 | };
455 |
456 | /*
457 | json2.js
458 | 2013-05-26
459 |
460 | Public Domain.
461 |
462 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
463 |
464 | See http://www.JSON.org/js.html
465 |
466 |
467 | This code should be minified before deployment.
468 | See http://javascript.crockford.com/jsmin.html
469 |
470 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
471 | NOT CONTROL.
472 |
473 |
474 | This file creates a global JSON object containing two methods: stringify
475 | and parse.
476 |
477 | JSON.stringify(value, replacer, space)
478 | value any JavaScript value, usually an object or array.
479 |
480 | replacer an optional parameter that determines how object
481 | values are stringified for objects. It can be a
482 | function or an array of strings.
483 |
484 | space an optional parameter that specifies the indentation
485 | of nested structures. If it is omitted, the text will
486 | be packed without extra whitespace. If it is a number,
487 | it will specify the number of spaces to indent at each
488 | level. If it is a string (such as '\t' or ' '),
489 | it contains the characters used to indent at each level.
490 |
491 | This method produces a JSON text from a JavaScript value.
492 |
493 | When an object value is found, if the object contains a toJSON
494 | method, its toJSON method will be called and the result will be
495 | stringified. A toJSON method does not serialize: it returns the
496 | value represented by the name/value pair that should be serialized,
497 | or undefined if nothing should be serialized. The toJSON method
498 | will be passed the key associated with the value, and this will be
499 | bound to the value
500 |
501 | For example, this would serialize Dates as ISO strings.
502 |
503 | Date.prototype.toJSON = function (key) {
504 | function f(n) {
505 | // Format integers to have at least two digits.
506 | return n < 10 ? '0' + n : n;
507 | }
508 |
509 | return this.getUTCFullYear() + '-' +
510 | f(this.getUTCMonth() + 1) + '-' +
511 | f(this.getUTCDate()) + 'T' +
512 | f(this.getUTCHours()) + ':' +
513 | f(this.getUTCMinutes()) + ':' +
514 | f(this.getUTCSeconds()) + 'Z';
515 | };
516 |
517 | You can provide an optional replacer method. It will be passed the
518 | key and value of each member, with this bound to the containing
519 | object. The value that is returned from your method will be
520 | serialized. If your method returns undefined, then the member will
521 | be excluded from the serialization.
522 |
523 | If the replacer parameter is an array of strings, then it will be
524 | used to select the members to be serialized. It filters the results
525 | such that only members with keys listed in the replacer array are
526 | stringified.
527 |
528 | Values that do not have JSON representations, such as undefined or
529 | functions, will not be serialized. Such values in objects will be
530 | dropped; in arrays they will be replaced with null. You can use
531 | a replacer function to replace those with JSON values.
532 | JSON.stringify(undefined) returns undefined.
533 |
534 | The optional space parameter produces a stringification of the
535 | value that is filled with line breaks and indentation to make it
536 | easier to read.
537 |
538 | If the space parameter is a non-empty string, then that string will
539 | be used for indentation. If the space parameter is a number, then
540 | the indentation will be that many spaces.
541 |
542 | Example:
543 |
544 | text = JSON.stringify(['e', {pluribus: 'unum'}]);
545 | // text is '["e",{"pluribus":"unum"}]'
546 |
547 |
548 | text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
549 | // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
550 |
551 | text = JSON.stringify([new Date()], function (key, value) {
552 | return this[key] instanceof Date ?
553 | 'Date(' + this[key] + ')' : value;
554 | });
555 | // text is '["Date(---current time---)"]'
556 |
557 |
558 | JSON.parse(text, reviver)
559 | This method parses a JSON text to produce an object or array.
560 | It can throw a SyntaxError exception.
561 |
562 | The optional reviver parameter is a function that can filter and
563 | transform the results. It receives each of the keys and values,
564 | and its return value is used instead of the original value.
565 | If it returns what it received, then the structure is not modified.
566 | If it returns undefined then the member is deleted.
567 |
568 | Example:
569 |
570 | // Parse the text. Values that look like ISO date strings will
571 | // be converted to Date objects.
572 |
573 | myData = JSON.parse(text, function (key, value) {
574 | var a;
575 | if (typeof value === 'string') {
576 | a =
577 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
578 | if (a) {
579 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
580 | +a[5], +a[6]));
581 | }
582 | }
583 | return value;
584 | });
585 |
586 | myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
587 | var d;
588 | if (typeof value === 'string' &&
589 | value.slice(0, 5) === 'Date(' &&
590 | value.slice(-1) === ')') {
591 | d = new Date(value.slice(5, -1));
592 | if (d) {
593 | return d;
594 | }
595 | }
596 | return value;
597 | });
598 |
599 |
600 | This is a reference implementation. You are free to copy, modify, or
601 | redistribute.
602 | */
603 |
604 | /*jslint evil: true, regexp: true */
605 |
606 | /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
607 | call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
608 | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
609 | lastIndex, length, parse, prototype, push, replace, slice, stringify,
610 | test, toJSON, toString, valueOf
611 | */
612 |
613 |
614 | // Create a JSON object only if one does not already exist. We create the
615 | // methods in a closure to avoid creating global variables.
616 |
617 | const jsonStringify = (function () {
618 | "use strict";
619 |
620 | // eslint-disable-next-line
621 | var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
622 | gap,
623 | indent,
624 | meta = { // table of character substitutions
625 | "\b": "\\b",
626 | "\t": "\\t",
627 | "\n": "\\n",
628 | "\f": "\\f",
629 | "\r": "\\r",
630 | "\"": "\\\"",
631 | "\\": "\\\\"
632 | },
633 | rep;
634 |
635 |
636 | function quote(string) {
637 |
638 | // If the string contains no control characters, no quote characters, and no
639 | // backslash characters, then we can safely slap some quotes around it.
640 | // Otherwise we must also replace the offending characters with safe escape
641 | // sequences.
642 |
643 | escapable.lastIndex = 0;
644 | return escapable.test(string) ? "\"" + string.replace(escapable, function (a) {
645 | var c = meta[a];
646 | return typeof c === "string"
647 | ? c
648 | : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
649 | }) + "\"" : "\"" + string + "\"";
650 | }
651 |
652 |
653 | function str(key, holder) {
654 |
655 | // Produce a string from holder[key].
656 |
657 | var i, // The loop counter.
658 | k, // The member key.
659 | v, // The member value.
660 | length,
661 | mind = gap,
662 | partial,
663 | value = holder[key],
664 | isBigInt = value != null && (typeof value == "bigint");
665 |
666 | // If the value has a toJSON method, call it to obtain a replacement value.
667 |
668 | if (value && typeof value === "object" &&
669 | typeof value.toJSON === "function") {
670 | value = value.toJSON(key);
671 | }
672 |
673 | // If we were called with a replacer function, then call the replacer to
674 | // obtain a replacement value.
675 |
676 | if (typeof rep === "function") {
677 | value = rep.call(holder, key, value);
678 | }
679 |
680 | // What happens next depends on the value's type.
681 |
682 | switch (typeof value) {
683 | case "string":
684 | if (isBigInt) {
685 | return value;
686 | } else {
687 | return quote(value);
688 | }
689 |
690 | case "number":
691 |
692 | // JSON numbers must be finite. Encode non-finite numbers as null.
693 |
694 | return isFinite(value) ? String(value) : "null";
695 |
696 | case "boolean":
697 | case "null":
698 | case "bigint":
699 |
700 | // If the value is a boolean or null, convert it to a string. Note:
701 | // typeof null does not produce 'null'. The case is included here in
702 | // the remote chance that this gets fixed someday.
703 |
704 | // If the type is 'object', we might be dealing with an object or an array or
705 | // null.
706 |
707 | return String(value);
708 |
709 | case "object":
710 |
711 | // Due to a specification blunder in ECMAScript, typeof null is 'object',
712 | // so watch out for that case.
713 |
714 | if (!value) {
715 | return "null";
716 | }
717 |
718 | // Make an array to hold the partial results of stringifying this object value.
719 |
720 | gap += indent;
721 | partial = [];
722 |
723 | // Is the value an array?
724 |
725 | if (Object.prototype.toString.apply(value) === "[object Array]") {
726 |
727 | // The value is an array. Stringify every element. Use null as a placeholder
728 | // for non-JSON values.
729 |
730 | length = value.length;
731 | for (i = 0; i < length; i += 1) {
732 | partial[i] = str(i, value) || "null";
733 | }
734 |
735 | // Join all of the elements together, separated with commas, and wrap them in
736 | // brackets.
737 |
738 | v = partial.length === 0
739 | ? "[]"
740 | : gap
741 | ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]"
742 | : "[" + partial.join(",") + "]";
743 | gap = mind;
744 | return v;
745 | }
746 |
747 | // If the replacer is an array, use it to select the members to be stringified.
748 |
749 | if (rep && typeof rep === "object") {
750 | length = rep.length;
751 | for (i = 0; i < length; i += 1) {
752 | if (typeof rep[i] === "string") {
753 | k = rep[i];
754 | v = str(k, value);
755 | if (v) {
756 | partial.push(quote(k) + (gap ? ": " : ":") + v);
757 | }
758 | }
759 | }
760 | } else {
761 |
762 | // Otherwise, iterate through all of the keys in the object.
763 |
764 | Object.keys(value).forEach(function (k) {
765 | var v = str(k, value);
766 | if (v) {
767 | partial.push(quote(k) + (gap ? ": " : ":") + v);
768 | }
769 | });
770 | }
771 |
772 | // Join all of the member texts together, separated with commas,
773 | // and wrap them in braces.
774 |
775 | v = partial.length === 0
776 | ? "{}"
777 | : gap
778 | ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}"
779 | : "{" + partial.join(",") + "}";
780 | gap = mind;
781 | return v;
782 | }
783 | }
784 |
785 | // If the JSON object does not yet have a stringify method, give it one.
786 |
787 | return function (value, replacer, space) {
788 |
789 | // The stringify method takes a value and an optional replacer, and an optional
790 | // space parameter, and returns a JSON text. The replacer can be a function
791 | // that can replace values, or an array of strings that will select the keys.
792 | // A default replacer method can be provided. Use of the space parameter can
793 | // produce text that is more easily readable.
794 |
795 | var i;
796 | gap = "";
797 | indent = "";
798 |
799 | // If the space parameter is a number, make an indent string containing that
800 | // many spaces.
801 |
802 | if (typeof space === "number") {
803 | for (i = 0; i < space; i += 1) {
804 | indent += " ";
805 | }
806 |
807 | // If the space parameter is a string, it will be used as the indent string.
808 |
809 | } else if (typeof space === "string") {
810 | indent = space;
811 | }
812 |
813 | // If there is a replacer, it must be a function or an array.
814 | // Otherwise, throw an error.
815 |
816 | rep = replacer;
817 | if (replacer && typeof replacer !== "function" &&
818 | (typeof replacer !== "object" ||
819 | typeof replacer.length !== "number")) {
820 | throw new Error("JSON.stringify");
821 | }
822 |
823 | // Make a fake root object containing our value under the key of ''.
824 | // Return the result of stringifying the value.
825 |
826 | return str("", { "": value });
827 | };
828 |
829 | }());
830 |
831 | const parseJson = json_parse();
832 |
833 | let collapserElements, statusElement, jsonObject, copiedSelector, jsonSelector, jsonPath, selectedListItem, hoveredListItem, originalBody, supportBigInt;
834 | chrome.runtime.onMessage.addListener(message => {
835 | if (message.copy) {
836 | if (message.type == MENU_ID_COPY_PATH && jsonPath) {
837 | copyText(jsonPath);
838 | } else if (message.type == MENU_ID_COPY_VALUE || message.type == MENU_ID_COPY_JSON_VALUE) {
839 | let value = jsonObject;
840 | copiedSelector.forEach(propertyName => value = value[propertyName]);
841 | if (value) {
842 | if (supportBigInt) {
843 | value = jsonStringify(value);
844 | } else {
845 | value = JSON.stringify(value);
846 | }
847 | if (message.type == MENU_ID_COPY_VALUE) {
848 | copyText(value);
849 | } else if (message.type == MENU_ID_COPY_JSON_VALUE) {
850 | copyText(JSON.stringify(value));
851 | }
852 | }
853 | }
854 | }
855 | });
856 | init();
857 |
858 | async function init() {
859 | let preElement = document.body.childNodes[0];
860 | if (preElement && preElement.tagName != "PRE") {
861 | preElement = document.body.childNodes[1];
862 | }
863 | if (document.body && (preElement && preElement.tagName == "PRE" || document.body.children.length == 0)) {
864 | const textElement = document.body.children.length ? preElement : document.body;
865 | const options = await sendMessage({ getOptions: true });
866 | supportBigInt = options.supportBigInt;
867 | const jsonInfo = extractJsonInfo(textElement.innerText, options);
868 | if (jsonInfo) {
869 | originalBody = document.body.cloneNode(true);
870 | await processData(jsonInfo, options);
871 | }
872 | }
873 | }
874 |
875 | function extractJsonInfo(rawText, options) {
876 | const initialRawText = rawText;
877 | rawText = rawText.trim().replace(new RegExp(options.jsonPrefix), "").trim();
878 | let tokens;
879 | if (detectJson(rawText)) {
880 | return {
881 | text: rawText,
882 | offset: initialRawText.indexOf(rawText)
883 | };
884 | } else {
885 | tokens = rawText.match(/^([^\s(]*)\s*\(([\s\S]*)\)\s*;?$/);
886 | if (tokens && tokens[1] && tokens[2]) {
887 | if (detectJson(tokens[2].trim())) {
888 | return {
889 | functionName: tokens[1],
890 | text: tokens[2],
891 | offset: initialRawText.indexOf(tokens[2])
892 | };
893 | }
894 | }
895 | }
896 |
897 | function detectJson(text) {
898 | return (
899 | (text.charAt(0) == "[" && text.charAt(text.length - 1) == "]") ||
900 | (text.charAt(0) == "{" && text.charAt(1) != "-" && text.charAt(1) != "%" && text.charAt(text.length - 1) == "}")
901 | );
902 | }
903 | }
904 |
905 | async function processData(jsonInfo, options) {
906 | if ((window == top || options.injectInFrame) && jsonInfo && jsonInfo.text) {
907 | const json = jsonInfo.text;
908 | const result = await sendMessage({
909 | jsonToHTML: true,
910 | json,
911 | functionName: jsonInfo.functionName,
912 | supportBigInt
913 | });
914 | if (result.html) {
915 | displayUI(result.stylesheet, result.html, options);
916 | try {
917 | if (supportBigInt) {
918 | jsonObject = parseJson(json);
919 | } else {
920 | jsonObject = JSON.parse(json);
921 | }
922 | } catch (error) {
923 | // ignored
924 | }
925 | }
926 | if (result.error) {
927 | displayError(result.stylesheet, result.error, result.loc, jsonInfo.offset);
928 | }
929 | }
930 | }
931 |
932 | function displayError(theme, error, loc, offset) {
933 | const userStyleElement = document.createElement("style");
934 | const preElement = document.body.firstChild.firstChild;
935 | const textElement = preElement.textContent.substring(offset);
936 | const iconElement = document.createElement("span");
937 | const contentElement = document.createElement("div");
938 | const errorPositionElement = document.createElement("span");
939 | const containerElement = document.createElement("div");
940 | const closeButtonElement = document.createElement("div");
941 | const range = document.createRange();
942 | const ranges = [];
943 | let startRange = 0, indexRange = 0;
944 | userStyleElement.appendChild(document.createTextNode(theme));
945 | document.head.appendChild(userStyleElement);
946 | while (indexRange != -1) {
947 | indexRange = textElement.indexOf("\n", startRange);
948 | ranges.push(startRange);
949 | startRange = indexRange + 1;
950 | }
951 | startRange = ranges[loc.first_line - 1] + loc.first_column + offset;
952 | const endRange = ranges[loc.last_line - 1] + loc.last_column + offset;
953 | range.setStart(preElement, startRange);
954 | if (startRange == endRange - 1) {
955 | range.setEnd(preElement, startRange);
956 | } else {
957 | range.setEnd(preElement, endRange);
958 | }
959 | errorPositionElement.className = "error-position";
960 | range.surroundContents(errorPositionElement);
961 | iconElement.className = "error-icon";
962 | iconElement.textContent = "⚠";
963 | errorPositionElement.insertBefore(iconElement, errorPositionElement.firstChild);
964 | contentElement.className = "content";
965 | closeButtonElement.className = "close-error";
966 | closeButtonElement.addEventListener("click", onCloseError, false);
967 | contentElement.textContent = error;
968 | contentElement.appendChild(closeButtonElement);
969 | containerElement.className = "container";
970 | containerElement.appendChild(contentElement);
971 | errorPositionElement.parentNode.insertBefore(containerElement, errorPositionElement.nextSibling);
972 | displayToolbox(true);
973 |
974 | function onCloseError(event) {
975 | if (event.isTrusted) {
976 | contentElement.parentElement.removeChild(contentElement);
977 | }
978 | }
979 | }
980 |
981 | function displayUI(stylesheet, html, options) {
982 | document.body.removeAttribute("style");
983 | const userStyleElement = document.createElement("style");
984 | statusElement = document.createElement("div");
985 | userStyleElement.appendChild(document.createTextNode(stylesheet));
986 | document.head.appendChild(userStyleElement);
987 | document.body.innerHTML = html;
988 | collapserElements = document.querySelectorAll("#json .collapsible .collapsible");
989 | if (options.maxDepthLevelExpanded) {
990 | let selectorsCollapsedElements = "#json .collapsible ";
991 | for (let indexLevel = 0; indexLevel < options.maxDepthLevelExpanded; indexLevel++) {
992 | selectorsCollapsedElements += ".collapsible ";
993 | }
994 | document.querySelectorAll(selectorsCollapsedElements).forEach(element => element.parentElement.classList.add("collapsed"));
995 | }
996 | statusElement.className = "status";
997 | document.body.appendChild(statusElement);
998 | document.body.addEventListener("mouseover", onMouseMove, false);
999 | document.body.addEventListener("click", onMouseClick, false);
1000 | document.body.addEventListener("contextmenu", onContextMenu, false);
1001 | document.body.addEventListener("click", onToggleCollapsible, false);
1002 | displayToolbox();
1003 | }
1004 |
1005 | function displayToolbox(onlyViewSource) {
1006 | const viewSourceElement = document.createElement("a");
1007 | const toolboxElement = document.createElement("div");
1008 | let openCollapsiblesElement, closeCollapsiblesElement;
1009 | if (!onlyViewSource) {
1010 | openCollapsiblesElement = document.createElement("span");
1011 | closeCollapsiblesElement = document.createElement("span");
1012 | closeCollapsiblesElement.title = TITLE_CLOSE_COLLAPSIBLES;
1013 | closeCollapsiblesElement.innerText = LABEL_CLOSE_COLLAPSIBLES;
1014 | openCollapsiblesElement.title = TITLE_OPEN_COLLAPSIBLES;
1015 | openCollapsiblesElement.innerText = LABEL_OPEN_COLLAPSIBLES;
1016 | openCollapsiblesElement.addEventListener("click", onOpenCollapsibles, false);
1017 | closeCollapsiblesElement.addEventListener("click", onCloseCollapsibles, false);
1018 | toolboxElement.appendChild(openCollapsiblesElement);
1019 | }
1020 | toolboxElement.appendChild(viewSourceElement);
1021 | if (!onlyViewSource) {
1022 | toolboxElement.appendChild(closeCollapsiblesElement);
1023 | }
1024 | document.body.appendChild(toolboxElement);
1025 | toolboxElement.className = "toolbox";
1026 | viewSourceElement.title = TITLE_VIEW_SOURCE;
1027 | viewSourceElement.innerText = LABEL_VIEW_SOURCE;
1028 | viewSourceElement.addEventListener("click", onViewSource, false);
1029 | }
1030 |
1031 | function onToggleCollapsible(event) {
1032 | if (event.isTrusted) {
1033 | const target = event.target;
1034 | if (target.className == "collapser") {
1035 | const collapsed = target.parentNode.getElementsByClassName("collapsible")[0];
1036 | collapsed.parentNode.classList.toggle(CLASS_COLLAPSED);
1037 | event.stopImmediatePropagation();
1038 | }
1039 | }
1040 | }
1041 |
1042 | function onOpenCollapsibles(event) {
1043 | if (event.isTrusted) {
1044 | collapserElements.forEach(collapsed => collapsed.parentNode.classList.remove(CLASS_COLLAPSED));
1045 | }
1046 | }
1047 |
1048 | function onCloseCollapsibles(event) {
1049 | if (event.isTrusted) {
1050 | collapserElements.forEach(collapsed => collapsed.parentNode.classList.add(CLASS_COLLAPSED));
1051 | }
1052 | }
1053 |
1054 | function onViewSource(event) {
1055 | if (event.isTrusted) {
1056 | document.body.replaceWith(originalBody);
1057 | }
1058 | }
1059 |
1060 | function onMouseMove(event) {
1061 | if (event.isTrusted) {
1062 | jsonPath = "";
1063 | let element = getParentListItem(event.target);
1064 | if (element && event.target.tagName != TAG_LIST_ITEM) {
1065 | jsonSelector = [];
1066 | if (hoveredListItem) {
1067 | hoveredListItem.firstChild.classList.remove(CLASS_HOVERED);
1068 | }
1069 | hoveredListItem = element;
1070 | element.firstChild.classList.add(CLASS_HOVERED);
1071 | do {
1072 | if (element.parentNode.classList.contains("array")) {
1073 | const index = [].indexOf.call(element.parentNode.children, element);
1074 | jsonPath = "[" + index + "]" + jsonPath;
1075 | jsonSelector.unshift(index);
1076 | }
1077 | if (element.parentNode.classList.contains("obj")) {
1078 | const key = element.firstChild.firstChild.innerText;
1079 | if (REGEXP_IDENTIFIER.test(key)) {
1080 | jsonPath = "." + key + jsonPath;
1081 | } else {
1082 | jsonPath = "[" + JSON.stringify(key) + "]" + jsonPath;
1083 | }
1084 | jsonSelector.unshift(key);
1085 | }
1086 | element = element.parentNode.parentNode.parentNode;
1087 | } while (element.tagName == TAG_LIST_ITEM);
1088 | if (jsonPath.charAt(0) == ".") {
1089 | jsonPath = jsonPath.substring(1);
1090 | }
1091 | statusElement.innerText = jsonPath;
1092 | } else if (hoveredListItem) {
1093 | hoveredListItem.firstChild.classList.remove(CLASS_HOVERED);
1094 | hoveredListItem = null;
1095 | statusElement.innerText = "";
1096 | jsonSelector = [];
1097 | }
1098 | }
1099 | }
1100 |
1101 | function onMouseClick(event) {
1102 | if (event.isTrusted) {
1103 | const previousSelectedListItem = selectedListItem;
1104 | if (selectedListItem) {
1105 | selectedListItem.firstChild.classList.remove(CLASS_SELECTED);
1106 | selectedListItem = null;
1107 | }
1108 | const newSelectedListItem = getParentListItem(event.target);
1109 | if (newSelectedListItem && previousSelectedListItem != newSelectedListItem) {
1110 | selectedListItem = newSelectedListItem;
1111 | selectedListItem.firstChild.classList.add(CLASS_SELECTED);
1112 | }
1113 | }
1114 | }
1115 |
1116 | function onContextMenu(event) {
1117 | if (event.isTrusted) {
1118 | copiedSelector = jsonSelector ? Array.from(jsonSelector) : [];
1119 | }
1120 | }
1121 |
1122 | function getParentListItem(element) {
1123 | if (element.tagName != TAG_LIST_ITEM) {
1124 | while (element && element.tagName != TAG_LIST_ITEM) {
1125 | element = element.parentNode;
1126 | }
1127 | }
1128 | if (element && element.tagName == TAG_LIST_ITEM) {
1129 | return element;
1130 | }
1131 | }
1132 |
1133 | function copyText(value) {
1134 | const command = "copy";
1135 | document.addEventListener(command, listener);
1136 | document.execCommand(command);
1137 | document.removeEventListener(command, listener);
1138 |
1139 | function listener(event) {
1140 | event.clipboardData.setData("text/plain", value);
1141 | event.preventDefault();
1142 | }
1143 | }
1144 |
1145 | function sendMessage(message) {
1146 | return new Promise(resolve => chrome.runtime.sendMessage(message, result => resolve(result)));
1147 | }
--------------------------------------------------------------------------------