├── .editorconfig
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── inspect
├── Echo.svelte
├── Formatter.svelte
├── Getter.svelte
├── Inspect.svelte
├── PrimitiveBase.svelte
├── Property.svelte
├── PropertyList.svelte
├── Toggle.svelte
├── focus-actions.js
├── formatters
│ ├── ArrayFormatter.svelte
│ ├── BigIntFormatter.svelte
│ ├── BooleanFormatter.svelte
│ ├── DateFormatter.svelte
│ ├── ElementFormatter.svelte
│ ├── ErrorFormatter.svelte
│ ├── FallbackFormatter.svelte
│ ├── FunctionFormatter.svelte
│ ├── MapEntry.svelte
│ ├── MapFormatter.svelte
│ ├── NilFormatter.svelte
│ ├── NumberFormatter.svelte
│ ├── ObjectFormatter.svelte
│ ├── RegExpFormatter.svelte
│ ├── SetFormatter.svelte
│ ├── StringFormatter.svelte
│ ├── SymbolFormatter.svelte
│ └── TypedArrayFormatter.svelte
└── utilities.js
├── package.json
└── svelte-inspect.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | charset = utf-8
3 | end_of_line = lf
4 | insert_final_newline = true
5 | trim_trailing_whitespace = true
6 |
7 | indent_style = space
8 | indent_size = 2
9 |
10 | root = true
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | public/bundle.*
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 0.1.3
4 | - Fix repeated slot names, which are no longer supported by Svelte.
5 |
6 | ## 0.1.2
7 | - Support configuration even in SSR mode.
8 | - Clean up MapEntry.svelte to avoid unused CSS warning.
9 |
10 | ## 0.1.1
11 | - Allow logging a single value with ``, without formatting as a variable.
12 | - Print sequences of whitespace correctly in strings, object keys, regex source, element attribute values and Symbol keys
13 | - Add formatters for Map and Set
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 trbrc
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 all
13 | 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 THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Svelte Inspect
2 |
3 | Live & interactive object inspector for [Svelte](https://svelte.dev), inspired by DevTools.
4 |
5 | ```console
6 | npm install --save svelte-inspect
7 | ```
8 |
9 | Try the example in the [svelte.dev REPL](https://svelte.dev/repl/eb3b3ae5639544d78d7363e126b29896). Use mouse and keyboard to inspect the todos.
10 |
11 | ```html
12 |
25 |
26 |
27 |
28 |
29 |
30 | ```
31 |
32 | ## Types
33 |
34 | See [REPL demo of most of the types](https://svelte.dev/repl/06f3a93da3454c6982aa5a38c541a5b0). These types have special formatting:
35 |
36 | - Arrays (including TypedArrays)
37 | - Objects
38 | - Functions (including async functions)
39 | - Classes
40 | - Map and Set
41 | - RegExps
42 | - Dates
43 | - Booleans
44 | - undefined and null
45 | - Numbers (including BigInt)
46 | - Strings
47 | - Symbols
48 | - Errors
49 | - HTML elements
50 |
51 | There's support for enumerable and non-enumerable properties, symbol keys, `__proto__`, and getters (click to evaluate). It does not yet have any special support for e.g. iterators, promises.
52 |
53 | ## Keyboard navigation
54 |
55 | You can use your keyboard to move around in the object hierarchy.
56 |
57 | Keys | | Action
58 | :--- | :--- | :---
59 | A…Z 0…9 | Type anything | Jump using fuzzy matching
60 | ⇥ | Tab | Focus next
61 | ⇧⇥ | Shift + Tab | Focus previous
62 | ⯇ | Left | Close or step out
63 | ⯈ | Right | Open or step in
64 | ⯅ | Up | Focus previous
65 | ⯆ | Down | Focus next
66 | | Space | Toggle
67 | ↵ | Enter | Open & step in
68 | esc | Escape | Step out
69 |
70 | ## API
71 |
72 | ### `Inspect`
73 |
74 | Create one inspector for every value passed in as a prop, with default colors.
75 |
76 | ```html
77 |
80 |
81 |
82 | ```
83 |
84 | ### `Inspect.Value`
85 |
86 | Inspect a single `value`, without showing the name of the prop. Also takes an optional `depth` directly as a prop.
87 |
88 | ```html
89 |
96 |
97 |
98 | ```
99 |
100 | ### `Inspect.Inverted`
101 |
102 | Inspector with color palette suitable for dark backgrounds.
103 |
104 | ```html
105 |
112 |
113 |
114 | ```
115 |
116 | ### `Inspect[0-10]`
117 |
118 | Inspectors pre-configured with `{depth: 0-10}`.
119 |
120 | ```html
121 |
124 |
125 |
126 | ```
127 |
128 | ### `Inspect.configure(configuration)`
129 |
130 | Create an inspect component with custom configuration.
131 |
132 | ```html
133 |
142 |
143 |
144 | ```
145 |
146 | Note the use of [`context="module"`](https://svelte.dev/docs#script_context_module), which is required for the Svelte compiler to understand that `CustomInspector` can be used in the template.
147 |
148 | The config is WIP. There are currently two options:
149 |
150 | #### `{depth: number}`
151 |
152 | Set how many levels of the object hierarchy should start in the open state. Defaults to `1`.
153 |
154 | ```html
155 |
164 |
165 |
166 |
167 | ```
168 |
169 | Non-enumerable properties will not be opened.
170 |
171 | #### `{palette: {...colors}}`
172 |
173 | Create a component with a customized color palette. Values are any valid CSS color, keys are `red`, `blue`, `green`, `purple`, `orange`, `yellow`, `brown`, `pink`, `gray`, `black`, `white` and `selection` (note that not all of these colors are currently used).
174 |
175 | *(work in progress; expect to change)*
176 |
177 | ```html
178 |
187 | ```
188 |
--------------------------------------------------------------------------------
/inspect/Echo.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/inspect/Formatter.svelte:
--------------------------------------------------------------------------------
1 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/inspect/Getter.svelte:
--------------------------------------------------------------------------------
1 |
27 |
28 | {#if hasGottenResult}
29 |
30 | get
31 |
32 |
33 | {:else}
34 |
38 | get
39 |
40 | {#if hasError}
41 | {getterError}
42 | {:else}
43 | (…)
44 | {/if}
45 |
46 | {/if}
47 |
48 |
65 |
--------------------------------------------------------------------------------
/inspect/Inspect.svelte:
--------------------------------------------------------------------------------
1 |
24 |
25 | {#if valueOnly}
26 |
27 |
31 |
32 | {:else}
33 | {#each propKeys as key}
34 |
35 |
42 |
43 | {/each}
44 | {/if}
45 |
46 |
86 |
--------------------------------------------------------------------------------
/inspect/PrimitiveBase.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
14 | {#if !isOpen}
15 | …
16 | {:else}
17 | {
18 | {/if}
19 |
20 |
21 | {#if isOpen}
22 |
25 | }
26 | {/if}
27 |
28 |
37 |
--------------------------------------------------------------------------------
/inspect/Property.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
22 |
23 | {String(key)}{separator}
24 |
25 |
26 |
27 |
44 |
--------------------------------------------------------------------------------
/inspect/PropertyList.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 | {#each properties.slice(0, maxCount) as property (property)}
20 |
32 | {:else}
33 |
34 |
35 |
No properties
36 |
37 | {/each}
38 | {#if maxCount < properties.length}
39 | {#each {length: 1} as _ (maxCount)}
40 |
41 |
42 |
{
44 | maxCount += paging;
45 | focusPrev();
46 | onTick(focusNext);
47 | }}
48 | >
49 | Show {maxCount} … {Math.min(properties.length, maxCount + paging - 1)} of {properties.length} properties
50 |
51 |
52 | {/each}
53 | {/if}
54 |
55 |
56 |
76 |
--------------------------------------------------------------------------------
/inspect/Toggle.svelte:
--------------------------------------------------------------------------------
1 |
20 |
21 |
98 |
99 | {
103 | if (event.detail === 1) {
104 | toggle();
105 | } else if (isOpen && event.detail === 2) {
106 | enterFocusScope();
107 | }
108 | }}
109 | on:keydown={onKeyDown}
110 | class:toggle={true}
111 | class={className}
112 | >
113 |
114 |
115 |
116 |
128 |
--------------------------------------------------------------------------------
/inspect/focus-actions.js:
--------------------------------------------------------------------------------
1 | let serialCounter = 0;
2 |
3 | export function target(element) {
4 | // This should probably not be a global serial, but based instead on the scope.
5 | element.dataset.focusTarget = serialCounter++;
6 | element.tabIndex = 0;
7 | const focusEventListener = () => {
8 | setFocus(element);
9 | };
10 | element.addEventListener('focus', focusEventListener);
11 | return {
12 | destroy() {
13 | element.removeEventListener('focus', focusEventListener);
14 | }
15 | };
16 | }
17 |
18 | export function scope(element) {
19 | element.dataset.focusScope = '';
20 | }
21 |
22 | const createRangeFrom = element => {
23 | const range = document.createRange();
24 | range.selectNodeContents(element);
25 | return range;
26 | };
27 |
28 | function getElementBefore(referenceElement, elements) {
29 | const range = createRangeFrom(referenceElement);
30 | const lastIndex = elements.length - 1;
31 | for (let i = lastIndex; i >= 0; i--) {
32 | if (range.comparePoint(elements[i], 0) === -1) {
33 | return elements[i];
34 | }
35 | }
36 | return elements[lastIndex];
37 | }
38 |
39 | function getElementAfter(referenceElement, elements) {
40 | const range = createRangeFrom(referenceElement);
41 | for (let i = 0; i < elements.length; i++) {
42 | if (range.comparePoint(elements[i], 0) === 1) {
43 | return elements[i];
44 | }
45 | }
46 | return elements[0];
47 | }
48 |
49 | function getTargetBefore(element) {
50 | return getElementBefore(
51 | element,
52 | document.querySelectorAll('[data-focus-target]')
53 | );
54 | }
55 |
56 | function getTargetAfter(element) {
57 | return getElementAfter(
58 | element,
59 | document.querySelectorAll('[data-focus-target]')
60 | );
61 | }
62 |
63 | function getParentScope(element) {
64 | return element.closest('[data-focus-scope]');
65 | }
66 |
67 | function setFocus(targetElement) {
68 | if (targetElement) {
69 | const serial = targetElement.dataset.focusTarget;
70 | if (serial) {
71 | const scope = getParentScope(targetElement);
72 | if (scope) {
73 | scope.dataset.focusScope = serial;
74 | }
75 | }
76 | targetElement.focus();
77 | return true;
78 | }
79 | return false;
80 | }
81 |
82 | export function focusPrev() {
83 | return setFocus(getTargetBefore(document.activeElement));
84 | }
85 |
86 | export function focusNext() {
87 | return setFocus(getTargetAfter(document.activeElement));
88 | }
89 |
90 | export function exitFocusScope() {
91 | const parent = getParentScope(document.activeElement);
92 | if (parent) {
93 | return setFocus(getTargetBefore(parent));
94 | } else {
95 | document.activeElement.blur();
96 | return false;
97 | }
98 | }
99 |
100 | export function enterFocusScope() {
101 | const nextScope = getElementAfter(
102 | document.activeElement,
103 | document.querySelectorAll('[data-focus-scope]')
104 | );
105 | const targetBefore = getTargetBefore(nextScope);
106 | if (targetBefore !== document.activeElement) {
107 | // We only want to enter the scope if it is directly after activeElement
108 | return false;
109 | }
110 | const serial = nextScope.dataset.focusScope;
111 | const selector = serial
112 | ? `[data-focus-target="${serial}"]`
113 | : `[data-focus-target]`;
114 | const target = nextScope.querySelector(selector);
115 | return setFocus(target);
116 | }
117 |
118 | export function focusBySearch(string) {
119 | // Find a focus target that matches the string.
120 | try {
121 | const regex = new RegExp(string.split('').join('[^a-z0-9]*.?[^a-z0-9]*'), 'i');
122 | let scope = (document.activeElement);
123 | do {
124 | scope = getParentScope(scope.parentElement);
125 | const targets = (scope || document).querySelectorAll('[data-focus-target]');
126 | for (let i = 0; i < targets.length; i++) {
127 | const target = targets[i];
128 | const text = target.textContent;
129 | if (regex.test(text)) {
130 | return setFocus(target);
131 | }
132 | }
133 | } while (scope);
134 | } catch (e) {}
135 | return false;
136 | }
137 |
138 |
--------------------------------------------------------------------------------
/inspect/formatters/ArrayFormatter.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
16 |
17 |
18 |
19 |
20 | Array(
21 | {value.length}
22 | )
23 |
24 | [{#if !isOpen}
25 | …]
26 | {/if}
27 |
28 |
29 | {#if isOpen}
30 |
34 | Empty array
35 |
36 | ]
37 | {/if}
38 |
39 |
54 |
--------------------------------------------------------------------------------
/inspect/formatters/BigIntFormatter.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
12 |
13 |
14 |
15 | {#each stringified.split(/(\d+)/) as group, index}
16 | {#if group.length}
17 | {group}
18 | {/if}
19 | {/each}
20 |
21 |
22 |
30 |
--------------------------------------------------------------------------------
/inspect/formatters/BooleanFormatter.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
11 |
12 |
13 | {String(value)}
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/inspect/formatters/DateFormatter.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
20 |
21 |
22 |
23 |
24 | Date(
25 |
26 | {#each grouper(date) as {key, match}}
27 | {match}
28 | {/each}
29 |
30 |
31 | {#each grouper(time) as {key, match}}
32 | {match}
33 | {/each}
34 |
35 | )
36 |
37 |
38 |
39 |
50 |
--------------------------------------------------------------------------------
/inspect/formatters/ElementFormatter.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
21 |
22 |
23 |
24 |
25 | <
26 | {value.tagName.toLowerCase()}
27 |
28 | {#each value.attributes as attribute}
29 | {' '}
30 | {#if attribute.value}
31 |
32 | {attribute.name}
33 | ="
34 | {attribute.value}
35 | "
36 |
37 | {:else}
38 |
39 | {attribute.name}
40 |
41 | {/if}
42 | {/each}
43 |
44 | >
45 |
46 |
47 |
48 |
63 |
--------------------------------------------------------------------------------
/inspect/formatters/ErrorFormatter.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
11 |
12 |
13 | {String(value)}
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/inspect/formatters/FallbackFormatter.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
11 |
12 |
13 | {String(value)}
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/inspect/formatters/FunctionFormatter.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
20 |
21 |
22 |
23 |
24 | {#each grouper(functionString) as {key, match}}
25 | {match}
26 | {/each}
27 |
28 |
29 |
30 |
47 |
--------------------------------------------------------------------------------
/inspect/formatters/MapEntry.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 | {#if !isOpen}
17 | {String(key)} => {String(value)} …
18 | {/if}
19 |
20 |
21 | {#if isOpen}
22 | {
23 |
27 | }
28 | {/if}
29 |
30 |
39 |
--------------------------------------------------------------------------------
/inspect/formatters/MapFormatter.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
19 |
20 |
21 |
22 |
23 | Map(
24 | {value.size}
25 | )
26 |
27 | {{#if !isOpen}
28 | …}
29 | {/if}
30 |
31 |
32 | {#if isOpen}
33 | {#each [...value] as [entryKey, entryValue], index (entryKey)}
34 |
35 |
36 |
37 | entry {index}:
38 |
39 |
40 | {:else}
41 |
42 |
43 |
No entries
44 |
45 | {/each}
46 |
50 | No properties
51 |
52 | }
53 | {/if}
54 |
55 |
91 |
--------------------------------------------------------------------------------
/inspect/formatters/NilFormatter.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
11 |
12 |
13 | {String(value)}
14 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/inspect/formatters/NumberFormatter.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
12 |
13 |
14 |
15 | {#each stringified.split(/(\d+)/) as group, index}
16 | {#if group.length}
17 | {group}
18 | {/if}
19 | {/each}
20 |
21 |
22 |
30 |
--------------------------------------------------------------------------------
/inspect/formatters/ObjectFormatter.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
19 |
20 |
21 |
22 | {typeDescription}
23 | {{#if !isOpen}
24 | …}
25 | {/if}
26 |
27 |
28 | {#if isOpen}
29 |
33 | }
34 | {/if}
35 |
36 |
48 |
--------------------------------------------------------------------------------
/inspect/formatters/RegExpFormatter.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
14 |
15 |
16 |
17 |
18 |
19 | /
20 | {source}
21 | /
22 | {flags}
23 |
24 |
25 |
26 |
27 |
39 |
--------------------------------------------------------------------------------
/inspect/formatters/SetFormatter.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
19 |
20 |
21 |
22 |
23 | Set(
24 | {value.size}
25 | )
26 |
27 | {{#if !isOpen}
28 | …}
29 | {/if}
30 |
31 |
32 | {#if isOpen}
33 | {#each [...value] as entryValue, index (entryValue)}
34 |
35 |
36 |
37 | entry {index}:
38 |
39 |
40 | {:else}
41 |
42 |
43 |
No entries
44 |
45 | {/each}
46 |
50 | No properties
51 |
52 | }
53 | {/if}
54 |
55 |
91 |
--------------------------------------------------------------------------------
/inspect/formatters/StringFormatter.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
14 |
15 |
16 |
17 |
18 | {#each groups as group}
19 | {group}
23 | {/each}
24 |
25 |
26 |
27 |
41 |
--------------------------------------------------------------------------------
/inspect/formatters/SymbolFormatter.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
15 |
16 |
17 |
18 |
19 | {prefix}
20 | {key}
21 | )
22 |
23 |
24 |
25 |
34 |
--------------------------------------------------------------------------------
/inspect/formatters/TypedArrayFormatter.svelte:
--------------------------------------------------------------------------------
1 |
22 |
23 |
37 |
38 |
39 |
40 |
41 | {typeDescription}(
42 | {value.length}
43 | )
44 |
45 | [{#if !isOpen}
46 | …]
47 | {/if}
48 |
49 |
50 | {#if isOpen}
51 |
54 | Empty array
55 |
56 | ]
57 | {/if}
58 |
59 |
74 |
--------------------------------------------------------------------------------
/inspect/utilities.js:
--------------------------------------------------------------------------------
1 | export const isNil = (value = null) => value === null;
2 |
3 | export const keyIsIndex = key => String(parseInt(String(key))) === String(key);
4 |
5 | import {tick} from 'svelte';
6 |
7 | export const onTick = callback => tick().then(callback);
8 |
9 | export const getObjectToStringTag = object => Object.prototype.toString.call(object).slice(8, -1);
10 |
11 | export const getObjectTypeString = object => {
12 | const hasToStringTag = Symbol.toStringTag in object;
13 | if (hasToStringTag) {
14 | return getObjectToStringTag(object);
15 | }
16 |
17 | const prototype = Object.getPrototypeOf(object);
18 | const constructorName = prototype && prototype.constructor && prototype.constructor.name;
19 | const usefulConstructorName = constructorName && constructorName !== 'Object';
20 |
21 | return usefulConstructorName ? constructorName : getObjectToStringTag(object);
22 | };
23 |
24 | export const getAllProperties = object => {
25 | const enumerableKeys = [];
26 | for (const enumerableKey in object) {
27 | enumerableKeys.push(enumerableKey);
28 | }
29 | return [...new Set([
30 | ...enumerableKeys,
31 | ...Object.getOwnPropertyNames(object),
32 | ...Object.getOwnPropertySymbols(object),
33 | ...(object['__proto__'] ? ['__proto__'] : [])
34 | ])];
35 | };
36 |
37 | export const getPropertyDescriptor = (object, prop) => {
38 | if (!object) {
39 | return {};
40 | } else if (prop === '__proto__') {
41 | return {
42 | value: Object.getPrototypeOf(object)
43 | };
44 | } else {
45 | const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(object, prop);
46 | if (ownPropertyDescriptor) {
47 | return ownPropertyDescriptor;
48 | } else {
49 | const prototype = Object.getPrototypeOf(object);
50 | return getPropertyDescriptor(prototype, prop);
51 | }
52 | }
53 | };
54 |
55 | export const stringEscapeGroups = string => {
56 | // Split string into array of sequences of characters, with needed escapes broken out
57 | const characters = string.split(/([\x00-\x1F]+)/);
58 | return characters.map(char => JSON.stringify(char).slice(1, -1));
59 | };
60 |
61 | const backslashCharCode = '\\'.charCodeAt(0);
62 |
63 | export const isEscapeGroup = string => string.charCodeAt(0) === backslashCharCode;
64 |
65 | export const groupByRegexes = (regexes) => {
66 | const keys = Object.keys(regexes);
67 | return string => {
68 | const groups = [];
69 | let source = string;
70 | while (source.length) {
71 | let bestKey = null;
72 | let bestMatch = null;
73 | let bestIndex = source.length;
74 | for (const key of keys) {
75 | const regex = regexes[key];
76 | const match = source.match(regex);
77 | if (match && match.index < bestIndex) {
78 | bestKey = key;
79 | bestMatch = match[0];
80 | bestIndex = match.index;
81 | }
82 | }
83 | if (bestIndex > 0) {
84 | groups.push({key: undefined, match: source.slice(0, bestIndex)})
85 | }
86 | if (bestMatch) {
87 | groups.push({key: bestKey, match: bestMatch})
88 | source = source.slice(bestIndex + bestMatch.length);
89 | } else {
90 | break;
91 | }
92 | }
93 | return groups;
94 | };
95 | };
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-inspect",
3 | "version": "0.1.3",
4 | "description": "Svelte object inspector",
5 | "svelte": "svelte-inspect.js",
6 | "repository": "github:trbrc/svelte-inspect",
7 | "homepage": "https://github.com/trbrc/svelte-inspect",
8 | "bugs": "https://github.com/trbrc/svelte-inspect/issues",
9 | "keywords": [
10 | "svelte",
11 | "devtools"
12 | ],
13 | "peerDependencies": {
14 | "svelte": "^3.0.0"
15 | },
16 | "license": "MIT"
17 | }
18 |
--------------------------------------------------------------------------------
/svelte-inspect.js:
--------------------------------------------------------------------------------
1 | import SvelteInspect from './inspect/Inspect.svelte';
2 |
3 | function configure(configuration) {
4 | if (SvelteInspect.render) {
5 | // It's an SSR'd component. We need to wrap .render
6 | return {
7 | ...SvelteInspect,
8 | render(props) {
9 | return SvelteInspect.render({
10 | ...props,
11 | [Symbol.for('configuration')]: configuration
12 | })
13 | }
14 | };
15 | } else {
16 | // It's a client side component. We need to extend the class.
17 | return class ConfiguredInspect extends SvelteInspect {
18 | constructor(options) {
19 | const props = options.props || {};
20 | super({
21 | ...options,
22 | props: {
23 | ...props,
24 | [Symbol.for('configuration')]: configuration
25 | }
26 | });
27 | }
28 | };
29 | }
30 | };
31 |
32 | const invertedPalette = {
33 | red: 'red',
34 | blue: 'dodgerblue',
35 | green: 'yellowgreen',
36 | purple: 'violet',
37 | gray: '#808080',
38 | black: '#d0d0d0',
39 | white: '#202020',
40 | selection: 'darkblue'
41 | };
42 |
43 | const Inverted = configure({
44 | palette: invertedPalette
45 | });
46 |
47 | const Value = configure({
48 | valueOnly: true
49 | });
50 |
51 | SvelteInspect.configure = configure;
52 | SvelteInspect.Inverted = Inverted;
53 | SvelteInspect.Value = Value;
54 |
55 | for (let i = 0; i <= 10; i++) {
56 | SvelteInspect[i] = configure({depth: i});
57 | SvelteInspect.Inverted[i] = configure({depth: i, palette: invertedPalette});
58 | }
59 |
60 | export default SvelteInspect;
61 |
62 | export {configure, Inverted, Value};
63 |
--------------------------------------------------------------------------------