@nil-/doc 0.2.36 → 0.2.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -50
- package/components/Layout.svelte +32 -18
- package/components/Layout.svelte.d.ts +1 -0
- package/components/block/Block.svelte +34 -17
- package/components/block/Block.svelte.d.ts +1 -0
- package/components/block/Controls.svelte +6 -1
- package/components/block/Controls.svelte.d.ts +1 -0
- package/components/block/Instance.svelte +111 -7
- package/components/block/Params.svelte +15 -18
- package/components/block/Params.svelte.d.ts +1 -0
- package/components/block/Template.svelte +17 -150
- package/components/block/Template.svelte.d.ts +1 -0
- package/components/block/context.d.ts +2 -2
- package/components/block/context.js +2 -1
- package/components/block/controls/misc/Styler.svelte +3 -2
- package/components/context.d.ts +0 -1
- package/components/context.js +0 -6
- package/components/etc/Container.svelte +19 -19
- package/components/etc/Container.svelte.d.ts +3 -3
- package/components/etc/ThemeIcon.svelte +1 -7
- package/components/navigation/Nav.svelte +12 -8
- package/components/navigation/Nav.svelte.d.ts +1 -3
- package/components/navigation/Node.svelte +1 -1
- package/components/navigation/Tree.svelte +1 -1
- package/components/navigation/utils/fuzz.d.ts +1 -0
- package/components/navigation/utils/fuzz.js +119 -0
- package/components/navigation/utils/renamer.d.ts +9 -0
- package/components/navigation/utils/renamer.js +15 -0
- package/components/navigation/utils/sort.d.ts +2 -0
- package/components/navigation/utils/sort.js +3 -0
- package/components/navigation/{utils.d.ts → utils/sorter.d.ts} +2 -12
- package/components/navigation/{utils.js → utils/sorter.js} +1 -17
- package/index.d.ts +2 -1
- package/index.js +2 -1
- package/package.json +1 -1
|
@@ -1,162 +1,29 @@
|
|
|
1
|
-
<style>
|
|
2
|
-
div {
|
|
3
|
-
box-sizing: border-box;
|
|
4
|
-
}
|
|
5
1
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
padding-bottom: 10px;
|
|
9
|
-
padding-top: 10px;
|
|
10
|
-
grid-auto-rows: 1fr;
|
|
11
|
-
grid-auto-columns: auto;
|
|
12
|
-
grid-auto-flow: row;
|
|
13
|
-
border-radius: 5px;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.template.columns {
|
|
17
|
-
grid-auto-rows: auto;
|
|
18
|
-
grid-auto-columns: 1fr;
|
|
19
|
-
grid-auto-flow: column;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.template > .cside {
|
|
23
|
-
display: grid;
|
|
24
|
-
grid-template-columns: 1fr 550px;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.content {
|
|
28
|
-
min-height: 100px;
|
|
29
|
-
border-radius: 5px;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
div:not(.cside) > .misc {
|
|
33
|
-
border-bottom-left-radius: 5px;
|
|
34
|
-
border-bottom-right-radius: 5px;
|
|
35
|
-
user-select: none;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.template > .cside > .misc {
|
|
39
|
-
border-top-right-radius: 5px;
|
|
40
|
-
border-bottom-right-radius: 5px;
|
|
41
|
-
user-select: none;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.instance {
|
|
45
|
-
overflow: hidden;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.content,
|
|
49
|
-
.misc {
|
|
50
|
-
margin: 3px;
|
|
51
|
-
border-style: solid;
|
|
52
|
-
border-width: 1px;
|
|
53
|
-
padding: 1px;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/* scrollable */
|
|
57
|
-
.scrollable {
|
|
58
|
-
overflow: scroll;
|
|
59
|
-
scrollbar-width: none; /* Firefox */
|
|
60
|
-
-ms-overflow-style: none; /* IE and Edge */
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.scrollable::-webkit-scrollbar {
|
|
64
|
-
display: none;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/* colors */
|
|
68
|
-
.template {
|
|
69
|
-
color: hsl(0, 0%, 0%);
|
|
70
|
-
background-color: hsl(0, 2%, 70%);
|
|
71
|
-
transition: color 350ms, background-color 350ms;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.template.dark {
|
|
75
|
-
color-scheme: dark;
|
|
76
|
-
color: hsl(0, 0%, 80%);
|
|
77
|
-
background-color: hsl(0, 2%, 40%);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.content,
|
|
81
|
-
.misc {
|
|
82
|
-
border-color: hsl(0, 2%, 60%);
|
|
83
|
-
background-color: hsl(0, 0%, 100%);
|
|
84
|
-
transition: border-color 350ms, background-color 350ms;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
.dark .content,
|
|
88
|
-
.dark .misc {
|
|
89
|
-
border-color: hsl(0, 2%, 40%);
|
|
90
|
-
background-color: hsl(200, 4%, 14%);
|
|
91
|
-
}
|
|
92
|
-
</style>
|
|
93
|
-
|
|
94
|
-
<script>import { getParams, getDefaults } from "./context";
|
|
95
|
-
import { getControls, getControlsState } from "./context";
|
|
2
|
+
<script>import { beforeUpdate } from "svelte";
|
|
3
|
+
import { getDefaults, getParams, getOrientation } from "./context";
|
|
96
4
|
import { resolve } from "./utils";
|
|
97
|
-
import
|
|
98
|
-
import Controls from "./controls/Controls.svelte";
|
|
99
|
-
import { cquery } from "./action";
|
|
100
|
-
import { beforeUpdate } from "svelte";
|
|
5
|
+
import Instance from "./Instance.svelte";
|
|
101
6
|
const params = getParams();
|
|
102
|
-
const controls = getControls();
|
|
103
|
-
const controlsState = getControlsState();
|
|
104
7
|
const defaultsStore = getDefaults();
|
|
105
|
-
const
|
|
8
|
+
const orientation = getOrientation();
|
|
106
9
|
export let defaults = void 0;
|
|
107
10
|
export let noreset = false;
|
|
108
11
|
export let columns = false;
|
|
109
|
-
const reset = () => {
|
|
110
|
-
$params = [];
|
|
111
|
-
$defaultsStore = defaults;
|
|
112
|
-
};
|
|
113
12
|
$:
|
|
114
|
-
$defaultsStore
|
|
115
|
-
const resolveArgs = resolve;
|
|
13
|
+
$defaultsStore = defaults ?? {};
|
|
116
14
|
$:
|
|
117
|
-
|
|
15
|
+
$orientation = columns;
|
|
118
16
|
let key = false;
|
|
119
17
|
beforeUpdate(() => key = !key);
|
|
18
|
+
const resolveArgs = resolve;
|
|
19
|
+
const cast = (t) => t;
|
|
120
20
|
</script>
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
enabled: expanded && $controlsState.position === undefined
|
|
131
|
-
}}
|
|
132
|
-
>
|
|
133
|
-
{#if noreset}
|
|
134
|
-
<div class="content scrollable" class:dark={$isDark}>
|
|
135
|
-
<slot
|
|
136
|
-
id={param.id}
|
|
137
|
-
tag={param.tag}
|
|
138
|
-
props={resolveArgs(param.defaults, param.values)}
|
|
139
|
-
{key}
|
|
140
|
-
/>
|
|
141
|
-
</div>
|
|
142
|
-
{:else}
|
|
143
|
-
{#key key}
|
|
144
|
-
<div class="content scrollable" class:dark={$isDark}>
|
|
145
|
-
<slot
|
|
146
|
-
id={param.id}
|
|
147
|
-
tag={param.tag}
|
|
148
|
-
props={resolveArgs(param.defaults, param.values)}
|
|
149
|
-
{key}
|
|
150
|
-
/>
|
|
151
|
-
</div>
|
|
152
|
-
{/key}
|
|
153
|
-
{/if}
|
|
154
|
-
{#if expanded}
|
|
155
|
-
<div class="misc scrollable" class:dark={$isDark}>
|
|
156
|
-
<Controls infos={$controls} bind:values={param.values} />
|
|
157
|
-
</div>
|
|
158
|
-
{/if}
|
|
159
|
-
</div>
|
|
160
|
-
{/each}
|
|
161
|
-
</div>
|
|
162
|
-
|
|
21
|
+
<!--
|
|
22
|
+
@component
|
|
23
|
+
See [documentation](https://mono-doc.vercel.app/3-Components/2-Block/2-Template) for more details.
|
|
24
|
+
-->
|
|
25
|
+
{#each $params as param (param.id)}
|
|
26
|
+
<Instance defaults={resolveArgs($defaultsStore, param.values)} {noreset} let:key let:props>
|
|
27
|
+
<slot id={param.id} tag={param.tag} props={cast(props)} {key} />
|
|
28
|
+
</Instance>
|
|
29
|
+
{/each}
|
|
@@ -20,6 +20,7 @@ declare class __sveltets_Render<Args> {
|
|
|
20
20
|
export type TemplateProps<Args> = ReturnType<__sveltets_Render<Args>['props']>;
|
|
21
21
|
export type TemplateEvents<Args> = ReturnType<__sveltets_Render<Args>['events']>;
|
|
22
22
|
export type TemplateSlots<Args> = ReturnType<__sveltets_Render<Args>['slots']>;
|
|
23
|
+
/** See [documentation](https://mono-doc.vercel.app/3-Components/2-Block/2-Template) for more details. */
|
|
23
24
|
export default class Template<Args> extends SvelteComponentTyped<TemplateProps<Args>, TemplateEvents<Args>, TemplateSlots<Args>> {
|
|
24
25
|
}
|
|
25
26
|
export {};
|
|
@@ -7,7 +7,6 @@ export type Params = {
|
|
|
7
7
|
id: number;
|
|
8
8
|
tag: string;
|
|
9
9
|
values: Record<string, ValueType>;
|
|
10
|
-
defaults: Record<string, ValueType>;
|
|
11
10
|
};
|
|
12
11
|
export type ControlState = {
|
|
13
12
|
hide: boolean;
|
|
@@ -15,5 +14,6 @@ export type ControlState = {
|
|
|
15
14
|
};
|
|
16
15
|
export declare const initParams: () => Writable<Params[]>, getParams: () => Writable<Params[]>;
|
|
17
16
|
export declare const initControls: () => Writable<Control[]>, getControls: () => Writable<Control[]>;
|
|
18
|
-
export declare const initDefaults: () => Writable<Record<string, ValueType
|
|
17
|
+
export declare const initDefaults: () => Writable<Record<string, ValueType>>, getDefaults: () => Writable<Record<string, ValueType>>;
|
|
19
18
|
export declare const initControlsState: () => Writable<ControlState>, getControlsState: () => Writable<ControlState>;
|
|
19
|
+
export declare const initOrientation: () => Writable<boolean>, getOrientation: () => Writable<boolean>;
|
|
@@ -9,7 +9,8 @@ const create = (defaulter) => {
|
|
|
9
9
|
};
|
|
10
10
|
export const { init: initParams, get: getParams } = create(() => []);
|
|
11
11
|
export const { init: initControls, get: getControls } = create(() => []);
|
|
12
|
-
export const { init: initDefaults, get: getDefaults } = create(() =>
|
|
12
|
+
export const { init: initDefaults, get: getDefaults } = create(() => ({}));
|
|
13
13
|
export const { init: initControlsState, get: getControlsState } = create(() => ({
|
|
14
14
|
hide: false
|
|
15
15
|
}));
|
|
16
|
+
export const { init: initOrientation, get: getOrientation } = create(() => false);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script>import { getTheme } from "../../../context";
|
|
2
|
-
const
|
|
2
|
+
const dark = getTheme();
|
|
3
3
|
</script>
|
|
4
4
|
<style>
|
|
5
5
|
div {
|
|
@@ -36,6 +36,7 @@ const isDark = getTheme();
|
|
|
36
36
|
|
|
37
37
|
/* colors */
|
|
38
38
|
div > :global(div) {
|
|
39
|
+
transition: background-color 350ms;
|
|
39
40
|
background-color: hsl(0, 0%, 100%);
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -79,7 +80,7 @@ const isDark = getTheme();
|
|
|
79
80
|
</style>
|
|
80
81
|
|
|
81
82
|
|
|
82
|
-
<div class:dark={$
|
|
83
|
+
<div class:dark={$dark}>
|
|
83
84
|
<slot />
|
|
84
85
|
</div>
|
|
85
86
|
|
package/components/context.d.ts
CHANGED
package/components/context.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { setContext, getContext } from "svelte";
|
|
2
2
|
import { writable } from "svelte/store";
|
|
3
|
-
const root = Symbol();
|
|
4
|
-
export const inRoot = () => {
|
|
5
|
-
const value = getContext(root);
|
|
6
|
-
setContext(root, false);
|
|
7
|
-
return value !== false;
|
|
8
|
-
};
|
|
9
3
|
const theme = Symbol();
|
|
10
4
|
export const getTheme = () => getContext(theme);
|
|
11
5
|
export const initTheme = () => setContext(theme, writable(true));
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
height: 100%;
|
|
9
9
|
display: grid;
|
|
10
10
|
grid-template-areas:
|
|
11
|
-
"
|
|
11
|
+
"A"
|
|
12
12
|
"divider"
|
|
13
|
-
"
|
|
13
|
+
"B";
|
|
14
14
|
overflow: hidden;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
.container.vertical {
|
|
18
|
-
grid-template-areas: "
|
|
18
|
+
grid-template-areas: "A divider B";
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
.container > div {
|
|
@@ -76,19 +76,19 @@
|
|
|
76
76
|
background-color: var(--color-p);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
.container.moving:not(.
|
|
79
|
+
.container.moving:not(.b):not(.vertical) > .divider {
|
|
80
80
|
border-bottom: var(--color-s) solid 2.5px;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
.container.moving.
|
|
83
|
+
.container.moving.b:not(.vertical) > .divider {
|
|
84
84
|
border-top: var(--color-s) solid 2.5px;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
.container.moving:not(.
|
|
87
|
+
.container.moving:not(.b).vertical > .divider {
|
|
88
88
|
border-right: var(--color-s) solid 2.5px;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
.container.moving.vertical.
|
|
91
|
+
.container.moving.vertical.b > .divider {
|
|
92
92
|
border-left: var(--color-s) solid 2.5px;
|
|
93
93
|
}
|
|
94
94
|
</style>
|
|
@@ -97,10 +97,10 @@
|
|
|
97
97
|
import { tweened } from "svelte/motion";
|
|
98
98
|
import { createDraggable } from "./action";
|
|
99
99
|
import { getTheme } from "../context";
|
|
100
|
-
const
|
|
100
|
+
const dark = getTheme();
|
|
101
101
|
export let vertical = false;
|
|
102
102
|
export let offset = 0;
|
|
103
|
-
export let
|
|
103
|
+
export let b = false;
|
|
104
104
|
let width;
|
|
105
105
|
let height;
|
|
106
106
|
const { position, draggable } = createDraggable(offset);
|
|
@@ -119,7 +119,7 @@ $:
|
|
|
119
119
|
$:
|
|
120
120
|
$off = offset;
|
|
121
121
|
$:
|
|
122
|
-
style = !
|
|
122
|
+
style = !b ? `auto 5px ${$off}px` : `${$off}px 5px auto`;
|
|
123
123
|
const moving = writable(false);
|
|
124
124
|
const addLast = (v) => {
|
|
125
125
|
if (v > 10) {
|
|
@@ -149,8 +149,8 @@ const check = (v, flag, s) => {
|
|
|
149
149
|
<div
|
|
150
150
|
class="container"
|
|
151
151
|
class:vertical
|
|
152
|
-
class:
|
|
153
|
-
class:dark={$
|
|
152
|
+
class:b
|
|
153
|
+
class:dark={$dark}
|
|
154
154
|
class:moving={$moving}
|
|
155
155
|
bind:clientWidth={width}
|
|
156
156
|
bind:clientHeight={height}
|
|
@@ -158,9 +158,9 @@ const check = (v, flag, s) => {
|
|
|
158
158
|
style:grid-template-rows={!vertical ? style : null}
|
|
159
159
|
>
|
|
160
160
|
{#if width != null && height != null}
|
|
161
|
-
<div style:grid-area="
|
|
162
|
-
{#if check($off, !
|
|
163
|
-
<slot name="
|
|
161
|
+
<div style:grid-area="A">
|
|
162
|
+
{#if check($off, !b, span)}
|
|
163
|
+
<slot name="A" />
|
|
164
164
|
{/if}
|
|
165
165
|
</div>
|
|
166
166
|
<div class="divider">
|
|
@@ -168,7 +168,7 @@ const check = (v, flag, s) => {
|
|
|
168
168
|
class="overlay"
|
|
169
169
|
use:draggable={{
|
|
170
170
|
reset: () => offset,
|
|
171
|
-
reversed: !
|
|
171
|
+
reversed: !b,
|
|
172
172
|
vertical,
|
|
173
173
|
dbltap: dbltap,
|
|
174
174
|
tap: () => addLast($off),
|
|
@@ -176,9 +176,9 @@ const check = (v, flag, s) => {
|
|
|
176
176
|
}}
|
|
177
177
|
/>
|
|
178
178
|
</div>
|
|
179
|
-
<div style:grid-area="
|
|
180
|
-
{#if check($off,
|
|
181
|
-
<slot name="
|
|
179
|
+
<div style:grid-area="B">
|
|
180
|
+
{#if check($off, b, span)}
|
|
181
|
+
<slot name="B" />
|
|
182
182
|
{/if}
|
|
183
183
|
</div>
|
|
184
184
|
{/if}
|
|
@@ -3,14 +3,14 @@ declare const __propDef: {
|
|
|
3
3
|
props: {
|
|
4
4
|
vertical?: boolean | undefined;
|
|
5
5
|
offset?: number | undefined;
|
|
6
|
-
|
|
6
|
+
b?: boolean | undefined;
|
|
7
7
|
};
|
|
8
8
|
events: {
|
|
9
9
|
[evt: string]: CustomEvent<any>;
|
|
10
10
|
};
|
|
11
11
|
slots: {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
A: {};
|
|
13
|
+
B: {};
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
16
|
export type ContainerProps = typeof __propDef.props;
|
|
@@ -44,13 +44,7 @@ const vdark = {
|
|
|
44
44
|
v: 1
|
|
45
45
|
};
|
|
46
46
|
</script>
|
|
47
|
-
<svg
|
|
48
|
-
class:dark
|
|
49
|
-
viewBox="-25 -25 50 50"
|
|
50
|
-
transform={`rotate(${$values.rotate})`}
|
|
51
|
-
on:click={() => (dark = !dark)}
|
|
52
|
-
on:keypress={null}
|
|
53
|
-
>
|
|
47
|
+
<svg class:dark viewBox="-25 -25 50 50" transform={`rotate(${$values.rotate})`}>
|
|
54
48
|
<mask id={`nil_doc_theme_icon_${index}`}>
|
|
55
49
|
<rect x="-25" y="-25" fill="white" />
|
|
56
50
|
<circle cy={$values.mcy} r="11" />
|
|
@@ -3,20 +3,22 @@
|
|
|
3
3
|
width: 100%;
|
|
4
4
|
height: 100%;
|
|
5
5
|
min-width: 200px;
|
|
6
|
-
gap: 10px;
|
|
7
6
|
display: flex;
|
|
8
7
|
flex-direction: column;
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
.logo,
|
|
12
10
|
.search-bar {
|
|
13
|
-
padding
|
|
14
|
-
padding-right: 20px;
|
|
11
|
+
padding: 5px;
|
|
15
12
|
}
|
|
16
13
|
|
|
17
14
|
input {
|
|
18
|
-
height:
|
|
15
|
+
height: 30px;
|
|
19
16
|
width: 100%;
|
|
17
|
+
padding: 0px 10px;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
input:focus {
|
|
21
|
+
outline: none;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
* {
|
|
@@ -26,7 +28,8 @@
|
|
|
26
28
|
}
|
|
27
29
|
</style>
|
|
28
30
|
|
|
29
|
-
<script context="module">
|
|
31
|
+
<script context="module">import { fuzz } from "./utils/fuzz";
|
|
32
|
+
const apply = (paths, init, pre, next, post) => {
|
|
30
33
|
const retval = {};
|
|
31
34
|
for (const path of paths) {
|
|
32
35
|
const parts = path.split("/");
|
|
@@ -51,7 +54,9 @@
|
|
|
51
54
|
}
|
|
52
55
|
return retval;
|
|
53
56
|
};
|
|
54
|
-
const filt = (path, filter, renamer) =>
|
|
57
|
+
const filt = (path, filter, renamer) => {
|
|
58
|
+
return fuzz(path, filter) || fuzz(path.split("/").map(renamer).join("/"), filter);
|
|
59
|
+
};
|
|
55
60
|
const populate = (filter, info, renamer) => apply(
|
|
56
61
|
filter.length > 0 ? info.filter((path) => filt(path, filter, renamer)) : info,
|
|
57
62
|
() => ({ url: null, sub: {} }),
|
|
@@ -91,7 +96,6 @@ $:
|
|
|
91
96
|
update(selected);
|
|
92
97
|
</script>
|
|
93
98
|
<div class="nav">
|
|
94
|
-
<div class="logo"><slot /></div>
|
|
95
99
|
<div class="search-bar">
|
|
96
100
|
<input bind:value={filter} type="text" />
|
|
97
101
|
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const fuzz: (target: string, query: string) => boolean;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
* See License.txt in https://github.com/microsoft/vscode/blob/main/LICENSE.txt
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
/*
|
|
7
|
+
* This implementation is inspired by:
|
|
8
|
+
* https://github.com/microsoft/vscode/blob/main/src/vs/base/common/fuzzyScorer.ts
|
|
9
|
+
*
|
|
10
|
+
* It is simplified to fit the use case for @nil-/doc
|
|
11
|
+
*/
|
|
12
|
+
const isUpper = (code) => {
|
|
13
|
+
// A == 65
|
|
14
|
+
// Z == 90
|
|
15
|
+
return 65 <= code && code <= 90;
|
|
16
|
+
};
|
|
17
|
+
const scoreSeparatorAtPos = (charCode) => {
|
|
18
|
+
switch (charCode) {
|
|
19
|
+
case 47: // Slash
|
|
20
|
+
// prefer path separators...
|
|
21
|
+
return 5;
|
|
22
|
+
case 95: // Underline
|
|
23
|
+
case 45: // Dash
|
|
24
|
+
case 46: // Period
|
|
25
|
+
case 32: // Space
|
|
26
|
+
case 58: // Colon:
|
|
27
|
+
// ...over other separators
|
|
28
|
+
return 4;
|
|
29
|
+
default:
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const computeCharScore = (queryCharAtIndex, queryLowerCharAtIndex, target, targetLower, targetIndex, matchesSequenceLength) => {
|
|
34
|
+
let score = 0;
|
|
35
|
+
if (queryLowerCharAtIndex !== targetLower[targetIndex]) {
|
|
36
|
+
// no match of characters
|
|
37
|
+
return score;
|
|
38
|
+
}
|
|
39
|
+
// Character match bonus
|
|
40
|
+
score += 1;
|
|
41
|
+
// Consecutive match bonus
|
|
42
|
+
if (matchesSequenceLength > 0) {
|
|
43
|
+
score += matchesSequenceLength * 5;
|
|
44
|
+
}
|
|
45
|
+
// Same case bonus
|
|
46
|
+
if (queryCharAtIndex === target[targetIndex]) {
|
|
47
|
+
score += 1;
|
|
48
|
+
}
|
|
49
|
+
// Start of word bonus
|
|
50
|
+
if (0 === targetIndex) {
|
|
51
|
+
score += 8;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const separatorBonus = scoreSeparatorAtPos(target.charCodeAt(targetIndex - 1));
|
|
55
|
+
if (separatorBonus) {
|
|
56
|
+
score += separatorBonus;
|
|
57
|
+
}
|
|
58
|
+
else if (isUpper(target.charCodeAt(targetIndex)) && 0 === matchesSequenceLength) {
|
|
59
|
+
score += 2;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return score;
|
|
63
|
+
};
|
|
64
|
+
const doScoreFuzzy = (query, queryLower, queryLength, target, targetLower, targetLength) => {
|
|
65
|
+
const scores = [];
|
|
66
|
+
const matches = [];
|
|
67
|
+
for (let queryIndex = 0; queryIndex < queryLength; queryIndex++) {
|
|
68
|
+
const queryIndexOffset = queryIndex * targetLength;
|
|
69
|
+
const queryIndexPreviousOffset = queryIndexOffset - targetLength;
|
|
70
|
+
const queryIndexGtNull = queryIndex > 0;
|
|
71
|
+
const queryCharAtIndex = query[queryIndex];
|
|
72
|
+
const queryLowerCharAtIndex = queryLower[queryIndex];
|
|
73
|
+
for (let targetIndex = 0; targetIndex < targetLength; targetIndex++) {
|
|
74
|
+
const targetIndexGtNull = targetIndex > 0;
|
|
75
|
+
const currentIndex = queryIndexOffset + targetIndex;
|
|
76
|
+
const leftIndex = currentIndex - 1;
|
|
77
|
+
const diagIndex = queryIndexPreviousOffset + targetIndex - 1;
|
|
78
|
+
const leftScore = targetIndexGtNull ? scores[leftIndex] : 0;
|
|
79
|
+
const diagScore = queryIndexGtNull && targetIndexGtNull ? scores[diagIndex] : 0;
|
|
80
|
+
const matchesSequenceLength = queryIndexGtNull && targetIndexGtNull ? matches[diagIndex] : 0;
|
|
81
|
+
const score = !diagScore && queryIndexGtNull
|
|
82
|
+
? 0
|
|
83
|
+
: computeCharScore(queryCharAtIndex, queryLowerCharAtIndex, target, targetLower, targetIndex, matchesSequenceLength);
|
|
84
|
+
const isValidScore = score && diagScore + score >= leftScore;
|
|
85
|
+
if (isValidScore) {
|
|
86
|
+
matches[currentIndex] = matchesSequenceLength + 1;
|
|
87
|
+
scores[currentIndex] = diagScore + score;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
matches[currentIndex] = 0;
|
|
91
|
+
scores[currentIndex] = leftScore;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const positions = [];
|
|
96
|
+
let queryIndex = queryLength - 1;
|
|
97
|
+
let targetIndex = targetLength - 1;
|
|
98
|
+
while (queryIndex >= 0 && targetIndex >= 0) {
|
|
99
|
+
const currentIndex = queryIndex * targetLength + targetIndex;
|
|
100
|
+
const match = matches[currentIndex];
|
|
101
|
+
if (0 === match) {
|
|
102
|
+
targetIndex--;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
positions.push(targetIndex);
|
|
106
|
+
queryIndex--;
|
|
107
|
+
targetIndex--;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return [scores[queryLength * targetLength - 1], positions.reverse()];
|
|
111
|
+
};
|
|
112
|
+
export const fuzz = (target, query) => {
|
|
113
|
+
const targetLength = target.length;
|
|
114
|
+
const queryLength = query.length;
|
|
115
|
+
if (targetLength < queryLength) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return (doScoreFuzzy(query, query.toLowerCase(), queryLength, target, target.toLowerCase(), targetLength)[0] > 0);
|
|
119
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const match = /(\d+)-(.+)/;
|
|
2
|
+
/**
|
|
3
|
+
* If a text follows `<I>-<Name>` format,
|
|
4
|
+
* this method simply removes the Prefix.
|
|
5
|
+
*
|
|
6
|
+
* @param text
|
|
7
|
+
* @returns `<Name>`
|
|
8
|
+
*/
|
|
9
|
+
export const renamer = (text) => {
|
|
10
|
+
const m = match.exec(text);
|
|
11
|
+
if (m) {
|
|
12
|
+
return m[2];
|
|
13
|
+
}
|
|
14
|
+
return text;
|
|
15
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Sorter } from "../types";
|
|
2
2
|
/**
|
|
3
3
|
* Compares two texts for sorting.
|
|
4
4
|
*
|
|
@@ -14,14 +14,4 @@ import type { Tree, Sorter, Renamer } from "./types";
|
|
|
14
14
|
* @param r - right operand
|
|
15
15
|
* @returns `-1 | 0 | +1`
|
|
16
16
|
*/
|
|
17
|
-
declare const sorter: Sorter;
|
|
18
|
-
/**
|
|
19
|
-
* If a text follows `<I>-<Name>` format,
|
|
20
|
-
* this method simply removes the Prefix.
|
|
21
|
-
*
|
|
22
|
-
* @param text
|
|
23
|
-
* @returns `<Name>`
|
|
24
|
-
*/
|
|
25
|
-
declare const renamer: Renamer;
|
|
26
|
-
export declare const sort: (t: Record<string, Tree>, order: (l: string, r: string) => 1 | 0 | -1) => [string, Tree][];
|
|
27
|
-
export { sorter, renamer };
|
|
17
|
+
export declare const sorter: Sorter;
|