fewrd 0.3.0 → 1.0.1
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/README.md +468 -176
- package/dist/index.js +1 -1
- package/dist/playground.js +157 -39
- package/dist/types/chart.d.ts +44 -0
- package/dist/types/conf.d.ts +45 -0
- package/dist/types/derive.d.ts +31 -0
- package/dist/types/dom.d.ts +33 -0
- package/dist/types/find.d.ts +12 -0
- package/dist/types/fold.d.ts +11 -0
- package/dist/types/grid.d.ts +27 -0
- package/dist/types/index.d.ts +5 -4
- package/dist/types/normalise.d.ts +1 -1
- package/dist/types/playground.d.ts +25 -27
- package/package.json +5 -6
- package/book.schema.json +0 -62
- package/dist/types/compile.d.ts +0 -26
- package/dist/types/read.d.ts +0 -3
- package/dist/types/render.d.ts +0 -21
- package/dist/types/types.d.ts +0 -123
|
@@ -1,34 +1,32 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import type { Book, Resolver } from './types.ts';
|
|
1
|
+
import { type Resolve } from './index.ts';
|
|
3
2
|
export interface PlaygroundCase {
|
|
4
3
|
name: string;
|
|
4
|
+
/** The key of the conf in `confs` this case is found with. */
|
|
5
|
+
conf: string;
|
|
5
6
|
text: string;
|
|
7
|
+
/** The tags folded when the case is first shown, and the gist that fold should give. */
|
|
8
|
+
fold?: string[];
|
|
9
|
+
gist?: string;
|
|
6
10
|
}
|
|
7
|
-
interface
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
fold?: Fold;
|
|
11
|
+
export interface PlaygroundConf {
|
|
12
|
+
conf: unknown;
|
|
13
|
+
resolvers?: Readonly<Record<string, Resolve>>;
|
|
11
14
|
}
|
|
12
|
-
export type MountOptions = (CommonOptions & {
|
|
13
|
-
book: Book;
|
|
14
|
-
})
|
|
15
|
-
/** Book data (e.g. parsed JSON) and its resolvers: the playground shows an editor and recompiles on every edit. */
|
|
16
|
-
| (CommonOptions & {
|
|
17
|
-
data: unknown;
|
|
18
|
-
resolvers?: Readonly<Record<string, Resolver>>;
|
|
19
|
-
/** Shows a save button: called with the editor's text once it parses as JSON. Reset then returns to what was saved. */
|
|
20
|
-
save?: (json: string) => unknown;
|
|
21
|
-
});
|
|
22
|
-
/** Distinct entities across a book's recipes, in first-appearance order. */
|
|
23
|
-
export declare function entities(book: Book): string[];
|
|
24
|
-
/** Which entities a supplied fold would fold across the given cases, or none if no fold was supplied. */
|
|
25
|
-
export declare function initialSelection(book: Book, cases: PlaygroundCase[], fold?: Fold): string[];
|
|
26
15
|
/**
|
|
27
|
-
* Mount
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
16
|
+
* Mount the playground on `el`: `confs` are named confs (data, typically JSON
|
|
17
|
+
* imports) with their resolvers, and every case says which one it uses. One case
|
|
18
|
+
* shows at a time, stepped with the buttons, the jump menu or the arrow keys; the
|
|
19
|
+
* editor shows the conf of the current case and recompiles it on every edit, so
|
|
20
|
+
* only that domain's cases change. Injects its own scoped styles; light and dark
|
|
21
|
+
* follow the OS unless the theme switch says otherwise.
|
|
22
|
+
*
|
|
23
|
+
* ponytail: the case is found again on every keystroke; debounce if a conf or a
|
|
24
|
+
* case ever makes typing lag. A character outside the BMP takes two string
|
|
25
|
+
* positions but one glyph, so bands after it drift by one `ch`; measure with
|
|
26
|
+
* Range rects if real subjects need it. A newline in a text is not handled. The
|
|
27
|
+
* tree is not keyboard-navigable: the bands are, and they light their tree rows.
|
|
32
28
|
*/
|
|
33
|
-
export declare function mount(el:
|
|
34
|
-
|
|
29
|
+
export declare function mount(el: HTMLElement, options: {
|
|
30
|
+
confs: Readonly<Record<string, PlaygroundConf>>;
|
|
31
|
+
cases: readonly PlaygroundCase[];
|
|
32
|
+
}): void;
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fewrd",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"description": "Finds what recurs in a string,
|
|
6
|
+
"description": "Finds what recurs in a string, and lets a reader fold it away.",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"text",
|
|
9
9
|
"segmentation",
|
|
@@ -20,8 +20,7 @@
|
|
|
20
20
|
"homepage": "https://github.com/egildo/fewrd#readme",
|
|
21
21
|
"bugs": "https://github.com/egildo/fewrd/issues",
|
|
22
22
|
"files": [
|
|
23
|
-
"dist"
|
|
24
|
-
"book.schema.json"
|
|
23
|
+
"dist"
|
|
25
24
|
],
|
|
26
25
|
"exports": {
|
|
27
26
|
".": {
|
|
@@ -31,12 +30,12 @@
|
|
|
31
30
|
"./playground": {
|
|
32
31
|
"types": "./dist/types/playground.d.ts",
|
|
33
32
|
"default": "./dist/playground.js"
|
|
34
|
-
}
|
|
35
|
-
"./book.schema.json": "./book.schema.json"
|
|
33
|
+
}
|
|
36
34
|
},
|
|
37
35
|
"scripts": {
|
|
38
36
|
"test": "node --test \"test/*.test.ts\"",
|
|
39
37
|
"typecheck": "tsc",
|
|
38
|
+
"bench": "node bench.ts",
|
|
40
39
|
"build": "vite build --config vite.lib.ts && tsc -p tsconfig.build.json",
|
|
41
40
|
"prepublishOnly": "npm run build",
|
|
42
41
|
"dev": "vite playground --port 5577 --strictPort"
|
package/book.schema.json
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"title": "fewrd book",
|
|
4
|
-
"description": "A fewrd recipe book written as data. Compile it with compile(data, { resolvers }) from 'fewrd'.",
|
|
5
|
-
"type": "object",
|
|
6
|
-
"properties": {
|
|
7
|
-
"$schema": {
|
|
8
|
-
"type": "string",
|
|
9
|
-
"description": "Where this schema is, e.g. ./node_modules/fewrd/book.schema.json. Ignored by compile."
|
|
10
|
-
},
|
|
11
|
-
"version": {
|
|
12
|
-
"type": "string",
|
|
13
|
-
"minLength": 1,
|
|
14
|
-
"description": "Keys a cached reading. Change it whenever a change to the recipes can change output."
|
|
15
|
-
},
|
|
16
|
-
"defs": {
|
|
17
|
-
"type": "object",
|
|
18
|
-
"description": "Named pattern fragments: source only, no slashes, no flags. Reference one from any pattern or fragment as %{NAME}; it splices in as one unit.",
|
|
19
|
-
"propertyNames": { "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" },
|
|
20
|
-
"additionalProperties": { "type": "string" }
|
|
21
|
-
},
|
|
22
|
-
"recipes": {
|
|
23
|
-
"type": "array",
|
|
24
|
-
"description": "Recipes in priority order.",
|
|
25
|
-
"items": { "$ref": "#/$defs/recipe" }
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
"required": ["version", "recipes"],
|
|
29
|
-
"additionalProperties": false,
|
|
30
|
-
"$defs": {
|
|
31
|
-
"pattern": {
|
|
32
|
-
"type": "string",
|
|
33
|
-
"pattern": "^/.*/[dgimsuvy]*$",
|
|
34
|
-
"description": "A regex as /source/flags, e.g. \"/C\\\\.?U\\\\.?P/iu\". %{NAME} splices in a fragment from defs."
|
|
35
|
-
},
|
|
36
|
-
"neighbour": {
|
|
37
|
-
"type": "object",
|
|
38
|
-
"properties": {
|
|
39
|
-
"part": { "type": "string", "minLength": 1, "description": "The part name this neighbour attaches as, e.g. label, date, unit." },
|
|
40
|
-
"rx": { "$ref": "#/$defs/pattern", "description": "Written plainly: the engine pins it to the anchor's edge." }
|
|
41
|
-
},
|
|
42
|
-
"required": ["part", "rx"],
|
|
43
|
-
"additionalProperties": false
|
|
44
|
-
},
|
|
45
|
-
"recipe": {
|
|
46
|
-
"type": "object",
|
|
47
|
-
"properties": {
|
|
48
|
-
"entity": { "type": "string", "minLength": 1, "description": "What this recipe recognises; mentions carry it." },
|
|
49
|
-
"anchor": { "$ref": "#/$defs/pattern", "description": "The value, strict. Its part is value (lead on a rest recipe)." },
|
|
50
|
-
"left": { "type": "array", "items": { "$ref": "#/$defs/neighbour" }, "description": "Neighbours tried leftward from the anchor, in priority order." },
|
|
51
|
-
"right": { "type": "array", "items": { "$ref": "#/$defs/neighbour" }, "description": "Neighbours tried rightward from the anchor, in priority order." },
|
|
52
|
-
"requires": { "type": "array", "items": { "type": "string" }, "description": "Parts that must attach, or the candidate is dropped." },
|
|
53
|
-
"resolve": { "type": "string", "minLength": 1, "description": "Name of a resolver passed to compile: canonical value from the parts, or null (not this entity after all)." },
|
|
54
|
-
"weak": { "type": "boolean", "description": "Fills only the gaps the strong recipes leave." },
|
|
55
|
-
"rest": { "type": "boolean", "description": "The mention runs from its anchor to the end of its level, and what follows is read again inside it. Neighbours are ignored." },
|
|
56
|
-
"glued": { "type": "boolean", "description": "The anchor may start or end inside a word." }
|
|
57
|
-
},
|
|
58
|
-
"required": ["entity", "anchor"],
|
|
59
|
-
"additionalProperties": false
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
package/dist/types/compile.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { Book, CompileError, CompileOptions } from './types.ts';
|
|
2
|
-
/** The keys each object accepts and requires. `book.schema.json` must agree (tested). */
|
|
3
|
-
export declare const KEYS: {
|
|
4
|
-
book: {
|
|
5
|
-
all: string[];
|
|
6
|
-
required: string[];
|
|
7
|
-
};
|
|
8
|
-
recipe: {
|
|
9
|
-
all: string[];
|
|
10
|
-
required: string[];
|
|
11
|
-
};
|
|
12
|
-
neighbour: {
|
|
13
|
-
all: string[];
|
|
14
|
-
required: string[];
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Compile a book written as data (typically `JSON.parse` output) into a Book.
|
|
19
|
-
* `resolve` names are looked up in `options.resolvers`; nothing in `data` is
|
|
20
|
-
* ever evaluated as code. A recipe with any error is left out; the others
|
|
21
|
-
* keep their order.
|
|
22
|
-
*/
|
|
23
|
-
export declare function compile(data: unknown, options?: CompileOptions): {
|
|
24
|
-
book: Book;
|
|
25
|
-
errors: CompileError[];
|
|
26
|
-
};
|
package/dist/types/read.d.ts
DELETED
package/dist/types/render.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { Cuts, Mention } from './types.ts';
|
|
2
|
-
export type Fold = (mention: Mention, index: number) => boolean;
|
|
3
|
-
/**
|
|
4
|
-
* Which leaves the condensed view shows. With nothing folded, every leaf.
|
|
5
|
-
*
|
|
6
|
-
* - A mention folds when the policy says so, or when the mention holding it folds.
|
|
7
|
-
* - A bracket pair folds when nothing between them survives.
|
|
8
|
-
* - The separators between two surviving leaves survive untouched when no
|
|
9
|
-
* fold fell among them; otherwise only the strongest one survives, and none
|
|
10
|
-
* at an edge, after an opening bracket or before closing punctuation.
|
|
11
|
-
*/
|
|
12
|
-
export declare function shown(cuts: Cuts, fold: Fold): boolean[];
|
|
13
|
-
/** The condensed view as plain text. */
|
|
14
|
-
export declare function gist(cuts: Cuts, fold: Fold): string;
|
|
15
|
-
/**
|
|
16
|
-
* Tagged HTML holding both views: every leaf is there, and what the condensed
|
|
17
|
-
* view drops carries `data-fold` — so `.condensed [data-fold] { display: none }`
|
|
18
|
-
* is the whole switch. Mentions are `<span data-entity data-mention>`, parts
|
|
19
|
-
* `<span data-part>`, separators `<span data-sep>`, nested as the mentions nest.
|
|
20
|
-
*/
|
|
21
|
-
export declare function html(cuts: Cuts, fold: Fold): string;
|
package/dist/types/types.d.ts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/** Half-open, indices into the ORIGINAL string. */
|
|
2
|
-
export interface Span {
|
|
3
|
-
start: number;
|
|
4
|
-
end: number;
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* A neighbour a recipe may attach beside its anchor. Write `rx` plainly: the
|
|
8
|
-
* engine pins it to the anchor's edge (`$` on the left, sticky on the right).
|
|
9
|
-
*/
|
|
10
|
-
export interface Neighbour {
|
|
11
|
-
part: string;
|
|
12
|
-
rx: RegExp;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* One pattern: a strict anchor, then a closed list of neighbours tried outward.
|
|
16
|
-
* Each neighbour attaches at most once; after every attachment the list is
|
|
17
|
-
* tried again from the top, so declaration order is priority at each step.
|
|
18
|
-
*/
|
|
19
|
-
export interface Recipe {
|
|
20
|
-
entity: string;
|
|
21
|
-
/** The value, strict. Its part is `value` (`lead` on a `rest` recipe). */
|
|
22
|
-
anchor: RegExp;
|
|
23
|
-
left?: readonly Neighbour[];
|
|
24
|
-
right?: readonly Neighbour[];
|
|
25
|
-
/** Parts that must attach, or the candidate is dropped. */
|
|
26
|
-
requires?: readonly string[];
|
|
27
|
-
/** Canonical value from the attached parts' text, or null: not this entity after all. */
|
|
28
|
-
resolve?: (parts: Readonly<Record<string, string>>) => string | null;
|
|
29
|
-
/** Fills only the gaps the strong recipes leave. */
|
|
30
|
-
weak?: boolean;
|
|
31
|
-
/**
|
|
32
|
-
* The mention runs from its anchor to the end of its level, and what follows
|
|
33
|
-
* the anchor is read again inside it. Neighbours are ignored.
|
|
34
|
-
*/
|
|
35
|
-
rest?: boolean;
|
|
36
|
-
/** The anchor may start or end inside a word. Default: it may not. */
|
|
37
|
-
glued?: boolean;
|
|
38
|
-
}
|
|
39
|
-
/** Recipes in priority order, and the version that keys a cached reading. */
|
|
40
|
-
export interface Book {
|
|
41
|
-
version: string;
|
|
42
|
-
recipes: readonly Recipe[];
|
|
43
|
-
}
|
|
44
|
-
/** A recipe's `resolve`, supplied by name at compile time. */
|
|
45
|
-
export type Resolver = NonNullable<Recipe['resolve']>;
|
|
46
|
-
/** A `Neighbour` as data. `rx` is a pattern: `"/source/flags"`. */
|
|
47
|
-
export interface NeighbourData {
|
|
48
|
-
part: string;
|
|
49
|
-
rx: string;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* A `Recipe` as data. Patterns are `"/source/flags"` strings, where
|
|
53
|
-
* `%{NAME}` splices in `BookData.defs.NAME` as one unit; `resolve` names a
|
|
54
|
-
* function from `CompileOptions.resolvers`.
|
|
55
|
-
*/
|
|
56
|
-
export interface RecipeData {
|
|
57
|
-
entity: string;
|
|
58
|
-
anchor: string;
|
|
59
|
-
left?: NeighbourData[];
|
|
60
|
-
right?: NeighbourData[];
|
|
61
|
-
requires?: string[];
|
|
62
|
-
resolve?: string;
|
|
63
|
-
weak?: boolean;
|
|
64
|
-
rest?: boolean;
|
|
65
|
-
glued?: boolean;
|
|
66
|
-
}
|
|
67
|
-
/** A `Book` as data: the JSON a book is written in. */
|
|
68
|
-
export interface BookData {
|
|
69
|
-
$schema?: string;
|
|
70
|
-
version: string;
|
|
71
|
-
/** Name → pattern source (no slashes, no flags), referenced as `%{NAME}`. */
|
|
72
|
-
defs?: Record<string, string>;
|
|
73
|
-
recipes: RecipeData[];
|
|
74
|
-
}
|
|
75
|
-
/** One problem found by `compile`. `recipe` indexes `BookData.recipes`. */
|
|
76
|
-
export interface CompileError {
|
|
77
|
-
/** Where in the data, e.g. `recipes[2].left[0].rx`; `""` is the root. */
|
|
78
|
-
path: string;
|
|
79
|
-
recipe?: number;
|
|
80
|
-
entity?: string;
|
|
81
|
-
message: string;
|
|
82
|
-
}
|
|
83
|
-
export interface CompileOptions {
|
|
84
|
-
resolvers?: Readonly<Record<string, Resolver>>;
|
|
85
|
-
}
|
|
86
|
-
export interface Mention {
|
|
87
|
-
entity: string;
|
|
88
|
-
/** Index into the book's recipes. */
|
|
89
|
-
recipe: number;
|
|
90
|
-
/** Every part, contiguous: what folding removes. */
|
|
91
|
-
extent: Span;
|
|
92
|
-
/** In text order. */
|
|
93
|
-
parts: {
|
|
94
|
-
part: string;
|
|
95
|
-
span: Span;
|
|
96
|
-
}[];
|
|
97
|
-
/** `resolve`'s answer, or the anchor's text. */
|
|
98
|
-
value: string;
|
|
99
|
-
/** The `rest` mention this one sits inside. */
|
|
100
|
-
parent?: number;
|
|
101
|
-
}
|
|
102
|
-
export type LeafKind = 'text' | 'sep' | 'open' | 'close' | 'part';
|
|
103
|
-
/**
|
|
104
|
-
* One piece of the partition. `mention` is the innermost mention holding it
|
|
105
|
-
* (a `text` or `sep` leaf may sit inside a `rest` mention).
|
|
106
|
-
*/
|
|
107
|
-
export interface Leaf {
|
|
108
|
-
start: number;
|
|
109
|
-
end: number;
|
|
110
|
-
kind: LeafKind;
|
|
111
|
-
part?: string;
|
|
112
|
-
mention?: number;
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* The cuts index: leaves partition `text` in order, no gap, no overlap —
|
|
116
|
-
* concatenating their slices gives `text` back, character for character.
|
|
117
|
-
*/
|
|
118
|
-
export interface Cuts {
|
|
119
|
-
text: string;
|
|
120
|
-
book: string;
|
|
121
|
-
mentions: Mention[];
|
|
122
|
-
leaves: Leaf[];
|
|
123
|
-
}
|