jaml-ui 0.21.2 → 0.21.4
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/DESIGN.md +36 -6
- package/dist/components/JamlAnalyzerFullscreen.d.ts +1 -1
- package/dist/components/JamlAnalyzerFullscreen.js +5 -81
- package/dist/components/JamlCurator.js +1 -1
- package/dist/components/JamlSpeedometer.d.ts +7 -2
- package/dist/components/JamlSpeedometer.js +8 -15
- package/dist/components/jamlMap/JamlMapEditor.js +42 -38
- package/dist/components/jamlMap/JokerPicker.js +2 -2
- package/dist/components/jamlMap/MysterySlot.js +4 -4
- package/dist/hooks/useSearch.d.ts +2 -1
- package/dist/hooks/useSearch.js +111 -8
- package/dist/lib/SpriteMapper.d.ts +10 -0
- package/dist/lib/SpriteMapper.js +48 -0
- package/dist/lib/cardParser.d.ts +8 -0
- package/dist/lib/cardParser.js +65 -0
- package/dist/lib/classes/BuyMetaData.d.ts +11 -0
- package/dist/lib/classes/BuyMetaData.js +1 -0
- package/dist/lib/config.d.ts +13 -0
- package/dist/lib/config.js +15 -0
- package/dist/lib/const.d.ts +61 -0
- package/dist/lib/const.js +521 -0
- package/dist/lib/data/constants.d.ts +11 -0
- package/dist/lib/data/constants.js +17 -0
- package/dist/lib/hooks/useDragScroll.d.ts +4 -0
- package/dist/lib/hooks/useDragScroll.js +48 -0
- package/dist/lib/hooks/useJamlFilter.d.ts +48 -0
- package/dist/lib/hooks/useJamlFilter.js +219 -0
- package/dist/lib/hooks/useSeedAnalyzer.d.ts +6 -0
- package/dist/lib/hooks/useSeedAnalyzer.js +48 -0
- package/dist/lib/jaml/jamlCompletion.d.ts +12 -0
- package/dist/lib/jaml/jamlCompletion.js +13 -0
- package/dist/lib/jaml/jamlData.d.ts +3 -0
- package/dist/lib/jaml/jamlData.js +8 -0
- package/dist/lib/jaml/jamlObjectives.d.ts +13 -0
- package/dist/lib/jaml/jamlObjectives.js +97 -0
- package/dist/lib/jaml/jamlParser.d.ts +14 -0
- package/dist/lib/jaml/jamlParser.js +47 -0
- package/dist/lib/jaml/jamlPresets.d.ts +8 -0
- package/dist/lib/jaml/jamlPresets.js +61 -0
- package/dist/lib/jaml/jamlSchema.d.ts +54 -0
- package/dist/lib/jaml/jamlSchema.js +91 -0
- package/dist/lib/parseDailyRitual.d.ts +45 -0
- package/dist/lib/parseDailyRitual.js +69 -0
- package/dist/lib/tts/getRevealPos.d.ts +5 -0
- package/dist/lib/tts/getRevealPos.js +16 -0
- package/dist/lib/tts/splitTtsDisplay.d.ts +19 -0
- package/dist/lib/tts/splitTtsDisplay.js +35 -0
- package/dist/lib/types.d.ts +121 -0
- package/dist/lib/types.js +1 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/ui/JimboIconButton.d.ts +10 -0
- package/dist/ui/JimboIconButton.js +28 -0
- package/dist/ui/JimboInputModal.d.ts +13 -0
- package/dist/ui/JimboInputModal.js +60 -0
- package/dist/ui/JimboSelect.d.ts +18 -0
- package/dist/ui/JimboSelect.js +43 -0
- package/dist/ui/PanelSplitter.d.ts +7 -0
- package/dist/ui/PanelSplitter.js +76 -0
- package/dist/ui/ide/AgnosticSeedCard.d.ts +19 -0
- package/dist/ui/ide/AgnosticSeedCard.js +48 -0
- package/dist/ui/ide/DeckSprite.d.ts +1 -0
- package/dist/ui/ide/DeckSprite.js +2 -0
- package/dist/ui/ide/JamlBuilder.d.ts +1 -0
- package/dist/ui/ide/JamlBuilder.js +112 -0
- package/dist/ui/ide/JamlEditor.d.ts +7 -0
- package/dist/ui/ide/JamlEditor.js +496 -0
- package/dist/ui/ide/JamlEditorMonaco.d.ts +8 -0
- package/dist/ui/ide/JamlEditorMonaco.js +78 -0
- package/dist/ui/ide/WasmStatus.d.ts +1 -0
- package/dist/ui/ide/WasmStatus.js +42 -0
- package/dist/ui/jimbo.css +336 -31
- package/dist/ui/jimboApp.d.ts +12 -0
- package/dist/ui/jimboApp.js +15 -0
- package/dist/ui/jimboInfoCard.d.ts +31 -0
- package/dist/ui/jimboInfoCard.js +26 -0
- package/dist/ui/jimboInset.d.ts +9 -0
- package/dist/ui/jimboInset.js +9 -0
- package/dist/ui/jimboSectionHeader.d.ts +11 -0
- package/dist/ui/jimboSectionHeader.js +9 -0
- package/dist/ui/jimboStatGrid.d.ts +13 -0
- package/dist/ui/jimboStatGrid.js +9 -0
- package/dist/ui/jimboWordmark.d.ts +10 -0
- package/dist/ui/jimboWordmark.js +9 -0
- package/dist/ui/mascot/JammySpeechBox.d.ts +9 -0
- package/dist/ui/mascot/JammySpeechBox.js +30 -0
- package/dist/ui/mascot/SeedMascot.d.ts +37 -0
- package/dist/ui/mascot/SeedMascot.js +17 -0
- package/dist/ui/mascot/index.d.ts +3 -0
- package/dist/ui/mascot/index.js +3 -0
- package/dist/ui/mascot/menuConfig.d.ts +102 -0
- package/dist/ui/mascot/menuConfig.js +12 -0
- package/dist/ui/panel.d.ts +1 -1
- package/dist/ui/panel.js +3 -21
- package/dist/ui/radial/RadialBadge.d.ts +17 -0
- package/dist/ui/radial/RadialBadge.js +43 -0
- package/dist/ui/radial/RadialBreadcrumb.d.ts +12 -0
- package/dist/ui/radial/RadialBreadcrumb.js +18 -0
- package/dist/ui/radial/RadialButton.d.ts +61 -0
- package/dist/ui/radial/RadialButton.js +102 -0
- package/dist/ui/radial/RadialMenu.d.ts +38 -0
- package/dist/ui/radial/RadialMenu.js +168 -0
- package/dist/ui/radial/RadialPill.d.ts +18 -0
- package/dist/ui/radial/RadialPill.js +15 -0
- package/dist/ui/radial/index.d.ts +16 -0
- package/dist/ui/radial/index.js +18 -0
- package/dist/ui/radial/radialMenuStore.d.ts +31 -0
- package/dist/ui/radial/radialMenuStore.js +122 -0
- package/dist/ui/radial/radialMenuViewport.d.ts +6 -0
- package/dist/ui/radial/radialMenuViewport.js +59 -0
- package/dist/ui/radial/useRadialMenu.d.ts +35 -0
- package/dist/ui/radial/useRadialMenu.js +107 -0
- package/dist/ui/showcase.d.ts +14 -6
- package/dist/ui/showcase.js +13 -21
- package/dist/ui/tokens.d.ts +5 -19
- package/dist/ui/tokens.js +5 -21
- package/dist/ui.d.ts +14 -0
- package/dist/ui.js +15 -0
- package/package.json +145 -146
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface JamlClause {
|
|
2
|
+
type: string;
|
|
3
|
+
value: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
antes?: number[];
|
|
6
|
+
score?: number;
|
|
7
|
+
edition?: string;
|
|
8
|
+
seal?: string;
|
|
9
|
+
enhancement?: string;
|
|
10
|
+
rank?: string;
|
|
11
|
+
suit?: string;
|
|
12
|
+
sources?: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface JamlFilter {
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
author: string;
|
|
18
|
+
deck: string;
|
|
19
|
+
stake: string;
|
|
20
|
+
defaults: {
|
|
21
|
+
antes: number[];
|
|
22
|
+
packSlots: number[];
|
|
23
|
+
shopSlots: number[];
|
|
24
|
+
score: number;
|
|
25
|
+
};
|
|
26
|
+
must: JamlClause[];
|
|
27
|
+
should: JamlClause[];
|
|
28
|
+
mustNot: JamlClause[];
|
|
29
|
+
}
|
|
30
|
+
import { DECK_OPTIONS, STAKE_OPTIONS, ANTE_OPTIONS, SLOT_OPTIONS, CLAUSE_TYPES, SOURCE_OPTIONS, EDITION_OPTIONS, SEAL_OPTIONS, ENHANCEMENT_OPTIONS } from '@/lib/data/constants';
|
|
31
|
+
export { DECK_OPTIONS, STAKE_OPTIONS, ANTE_OPTIONS, SLOT_OPTIONS, CLAUSE_TYPES, SOURCE_OPTIONS, EDITION_OPTIONS, SEAL_OPTIONS, ENHANCEMENT_OPTIONS };
|
|
32
|
+
export declare function useJamlFilter(initialJaml?: string): {
|
|
33
|
+
filter: JamlFilter;
|
|
34
|
+
jamlText: string;
|
|
35
|
+
setFromJaml: (text: string) => void;
|
|
36
|
+
updateFilter: (updates: Partial<JamlFilter>) => void;
|
|
37
|
+
addClause: (bucket: "must" | "should" | "mustNot", clause: JamlClause) => void;
|
|
38
|
+
editClause: (bucket: "must" | "should" | "mustNot", index: number, clause: JamlClause) => void;
|
|
39
|
+
deleteClause: (bucket: "must" | "should" | "mustNot", index: number) => void;
|
|
40
|
+
editingClause: {
|
|
41
|
+
bucket: keyof Pick<JamlFilter, "must" | "should" | "mustNot">;
|
|
42
|
+
index: number | null;
|
|
43
|
+
} | null;
|
|
44
|
+
setEditingClause: import("react").Dispatch<import("react").SetStateAction<{
|
|
45
|
+
bucket: keyof Pick<JamlFilter, "must" | "should" | "mustNot">;
|
|
46
|
+
index: number | null;
|
|
47
|
+
} | null>>;
|
|
48
|
+
};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { useState, useCallback, useMemo } from 'react';
|
|
2
|
+
import { DECK_OPTIONS, STAKE_OPTIONS, ANTE_OPTIONS, SLOT_OPTIONS, CLAUSE_TYPES, SOURCE_OPTIONS, EDITION_OPTIONS, SEAL_OPTIONS, ENHANCEMENT_OPTIONS } from '@/lib/data/constants';
|
|
3
|
+
export { DECK_OPTIONS, STAKE_OPTIONS, ANTE_OPTIONS, SLOT_OPTIONS, CLAUSE_TYPES, SOURCE_OPTIONS, EDITION_OPTIONS, SEAL_OPTIONS, ENHANCEMENT_OPTIONS };
|
|
4
|
+
export function useJamlFilter(initialJaml) {
|
|
5
|
+
const [filter, setFilter] = useState(parseJamlToFilter(initialJaml || ''));
|
|
6
|
+
const [editingClause, setEditingClause] = useState(null);
|
|
7
|
+
// useEffect removed to restore previous UX behavior
|
|
8
|
+
// The JAML from server (Rules format) parses to empty clauses,
|
|
9
|
+
// causing the UI to lose state after load. we want to keep the initial state.
|
|
10
|
+
const jamlText = useMemo(() => filterToJaml(filter), [filter]);
|
|
11
|
+
const updateFilter = useCallback((updates) => {
|
|
12
|
+
setFilter(prev => ({ ...prev, ...updates }));
|
|
13
|
+
}, []);
|
|
14
|
+
const addClause = useCallback((bucket, clause) => {
|
|
15
|
+
setFilter(prev => ({
|
|
16
|
+
...prev,
|
|
17
|
+
[bucket]: [...prev[bucket], clause]
|
|
18
|
+
}));
|
|
19
|
+
}, []);
|
|
20
|
+
const editClause = useCallback((bucket, index, clause) => {
|
|
21
|
+
setFilter(prev => ({
|
|
22
|
+
...prev,
|
|
23
|
+
[bucket]: prev[bucket].map((c, i) => i === index ? clause : c)
|
|
24
|
+
}));
|
|
25
|
+
}, []);
|
|
26
|
+
const deleteClause = useCallback((bucket, index) => {
|
|
27
|
+
setFilter(prev => ({
|
|
28
|
+
...prev,
|
|
29
|
+
[bucket]: prev[bucket].filter((_, i) => i !== index)
|
|
30
|
+
}));
|
|
31
|
+
}, []);
|
|
32
|
+
const setFromJaml = useCallback((text) => {
|
|
33
|
+
const newFilter = parseJamlToFilter(text);
|
|
34
|
+
setFilter(newFilter);
|
|
35
|
+
}, []);
|
|
36
|
+
return {
|
|
37
|
+
filter,
|
|
38
|
+
jamlText,
|
|
39
|
+
setFromJaml,
|
|
40
|
+
updateFilter,
|
|
41
|
+
addClause,
|
|
42
|
+
editClause,
|
|
43
|
+
deleteClause,
|
|
44
|
+
editingClause,
|
|
45
|
+
setEditingClause
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function parseJamlToFilter(text) {
|
|
49
|
+
if (!text.trim())
|
|
50
|
+
return createBlankFilter();
|
|
51
|
+
try {
|
|
52
|
+
const filter = createBlankFilter();
|
|
53
|
+
// Reset arrays to empty since we are parsing fresh
|
|
54
|
+
filter.must = [];
|
|
55
|
+
filter.should = [];
|
|
56
|
+
filter.mustNot = [];
|
|
57
|
+
const lines = text.split('\n');
|
|
58
|
+
let currentSection = null;
|
|
59
|
+
let currentClause = null;
|
|
60
|
+
for (const line of lines) {
|
|
61
|
+
const trimmed = line.trim();
|
|
62
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
63
|
+
continue;
|
|
64
|
+
// 1. Detect Section Headers
|
|
65
|
+
if (trimmed === 'must:') {
|
|
66
|
+
currentSection = 'must';
|
|
67
|
+
currentClause = null;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (trimmed === 'should:') {
|
|
71
|
+
currentSection = 'should';
|
|
72
|
+
currentClause = null;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (trimmed === 'mustNot:') {
|
|
76
|
+
currentSection = 'mustNot';
|
|
77
|
+
currentClause = null;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (trimmed === 'defaults:') {
|
|
81
|
+
currentSection = 'defaults';
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
// 2. Detect Root Properties (indent 0)
|
|
85
|
+
const rootMatch = line.match(/^(\w+):\s*(.+)$/);
|
|
86
|
+
if (rootMatch && !line.startsWith(' ') && !line.startsWith('-')) {
|
|
87
|
+
const [_, key, val] = rootMatch;
|
|
88
|
+
if (['name', 'deck', 'stake', 'description', 'author'].includes(key)) {
|
|
89
|
+
filter[key] = val.trim();
|
|
90
|
+
}
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
// 3. Handle Sections
|
|
94
|
+
if (currentSection) {
|
|
95
|
+
if (currentSection === 'defaults') {
|
|
96
|
+
const propMatch = trimmed.match(/^(\w+):\s*(.+)$/);
|
|
97
|
+
if (propMatch) {
|
|
98
|
+
const [_, key, val] = propMatch;
|
|
99
|
+
if (key === 'antes')
|
|
100
|
+
filter.defaults.antes = parseNumArray(val);
|
|
101
|
+
if (key === 'packSlots')
|
|
102
|
+
filter.defaults.packSlots = parseNumArray(val);
|
|
103
|
+
if (key === 'shopSlots')
|
|
104
|
+
filter.defaults.shopSlots = parseNumArray(val);
|
|
105
|
+
if (key === 'score')
|
|
106
|
+
filter.defaults.score = parseInt(val) || 0;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// Start of new clause
|
|
111
|
+
const typeMatch = trimmed.match(/^-\s*type:\s*(.+)$/);
|
|
112
|
+
if (typeMatch) {
|
|
113
|
+
currentClause = { type: typeMatch[1].trim(), value: '' };
|
|
114
|
+
filter[currentSection].push(currentClause);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// Properties of current clause
|
|
118
|
+
if (currentClause) {
|
|
119
|
+
const propMatch = trimmed.match(/^(\w+):\s*(.+)$/);
|
|
120
|
+
if (propMatch) {
|
|
121
|
+
const [_, key, val] = propMatch;
|
|
122
|
+
if (key === 'antes')
|
|
123
|
+
currentClause.antes = parseNumArray(val);
|
|
124
|
+
else if (key === 'sources')
|
|
125
|
+
currentClause.sources = parseStringArray(val);
|
|
126
|
+
else if (key === 'score')
|
|
127
|
+
currentClause.score = parseInt(val) || 0;
|
|
128
|
+
else
|
|
129
|
+
currentClause[key] = val.trim();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return filter;
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
console.warn('JAML Parse Error:', e);
|
|
139
|
+
return createBlankFilter();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function parseNumArray(str) {
|
|
143
|
+
return str.replace(/[\[\]]/g, '').split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
|
|
144
|
+
}
|
|
145
|
+
function parseStringArray(str) {
|
|
146
|
+
return str.replace(/[\[\]]/g, '').split(',').map(s => s.trim()).filter(s => !!s);
|
|
147
|
+
}
|
|
148
|
+
function filterToJaml(filter) {
|
|
149
|
+
const lines = [];
|
|
150
|
+
lines.push(`name: ${filter.name}`);
|
|
151
|
+
lines.push(`description: ${filter.description || ''}`);
|
|
152
|
+
lines.push(`author: ${filter.author || ''}`);
|
|
153
|
+
lines.push(`deck: ${filter.deck}`);
|
|
154
|
+
lines.push(`stake: ${filter.stake}`);
|
|
155
|
+
lines.push('');
|
|
156
|
+
lines.push('defaults:');
|
|
157
|
+
lines.push(` antes: [${filter.defaults.antes.join(', ')}]`);
|
|
158
|
+
lines.push(` packSlots: [${filter.defaults.packSlots.join(', ')}]`);
|
|
159
|
+
lines.push(` shopSlots: [${filter.defaults.shopSlots.join(', ')}]`);
|
|
160
|
+
lines.push(` score: ${filter.defaults.score}`);
|
|
161
|
+
lines.push('');
|
|
162
|
+
if (filter.must.length > 0) {
|
|
163
|
+
lines.push('must:');
|
|
164
|
+
filter.must.forEach(clause => lines.push(...clauseToLines(clause, ' ')));
|
|
165
|
+
}
|
|
166
|
+
if (filter.should.length > 0) {
|
|
167
|
+
lines.push('should:');
|
|
168
|
+
filter.should.forEach(clause => lines.push(...clauseToLines(clause, ' ')));
|
|
169
|
+
}
|
|
170
|
+
if (filter.mustNot.length > 0) {
|
|
171
|
+
lines.push('mustNot:');
|
|
172
|
+
filter.mustNot.forEach(clause => lines.push(...clauseToLines(clause, ' ')));
|
|
173
|
+
}
|
|
174
|
+
return lines.join('\n');
|
|
175
|
+
}
|
|
176
|
+
function clauseToLines(clause, indent) {
|
|
177
|
+
const lines = [];
|
|
178
|
+
lines.push(`${indent}- type: ${clause.type}`);
|
|
179
|
+
lines.push(`${indent} value: ${clause.value}`);
|
|
180
|
+
if (clause.label)
|
|
181
|
+
lines.push(`${indent} label: ${clause.label}`);
|
|
182
|
+
if (clause.antes && clause.antes.length > 0)
|
|
183
|
+
lines.push(`${indent} antes: [${clause.antes.join(', ')}]`);
|
|
184
|
+
if (clause.score)
|
|
185
|
+
lines.push(`${indent} score: ${clause.score}`);
|
|
186
|
+
if (clause.edition)
|
|
187
|
+
lines.push(`${indent} edition: ${clause.edition}`);
|
|
188
|
+
if (clause.seal)
|
|
189
|
+
lines.push(`${indent} seal: ${clause.seal}`);
|
|
190
|
+
if (clause.enhancement)
|
|
191
|
+
lines.push(`${indent} enhancement: ${clause.enhancement}`);
|
|
192
|
+
if (clause.rank)
|
|
193
|
+
lines.push(`${indent} rank: ${clause.rank}`);
|
|
194
|
+
if (clause.suit)
|
|
195
|
+
lines.push(`${indent} suit: ${clause.suit}`);
|
|
196
|
+
if (clause.sources && clause.sources.length > 0)
|
|
197
|
+
lines.push(`${indent} sources: [${clause.sources.join(', ')}]`);
|
|
198
|
+
return lines;
|
|
199
|
+
}
|
|
200
|
+
function createBlankFilter() {
|
|
201
|
+
return {
|
|
202
|
+
name: 'New Filter',
|
|
203
|
+
description: '',
|
|
204
|
+
author: '',
|
|
205
|
+
deck: 'Erratic',
|
|
206
|
+
stake: 'White',
|
|
207
|
+
defaults: {
|
|
208
|
+
antes: [...ANTE_OPTIONS],
|
|
209
|
+
packSlots: [...SLOT_OPTIONS],
|
|
210
|
+
shopSlots: [...SLOT_OPTIONS],
|
|
211
|
+
score: 1
|
|
212
|
+
},
|
|
213
|
+
must: [],
|
|
214
|
+
should: [
|
|
215
|
+
{ type: 'joker', value: 'Joker' }
|
|
216
|
+
],
|
|
217
|
+
mustNot: []
|
|
218
|
+
};
|
|
219
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import motely, { MotelyWasm } from 'motely-wasm';
|
|
4
|
+
export function useSeedAnalyzer(seed) {
|
|
5
|
+
const [data, setData] = useState(null);
|
|
6
|
+
const [loading, setLoading] = useState(false);
|
|
7
|
+
const [error, setError] = useState(null);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!seed || seed === "LOCKED") {
|
|
10
|
+
setData(null);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const abortController = new AbortController();
|
|
14
|
+
const runAnalysis = async () => {
|
|
15
|
+
setLoading(true);
|
|
16
|
+
setError(null);
|
|
17
|
+
try {
|
|
18
|
+
await motely.boot();
|
|
19
|
+
if (abortController.signal.aborted)
|
|
20
|
+
return;
|
|
21
|
+
const jaml = `version: 1\nconfig:\n deck: Erratic\n stake: White\n`;
|
|
22
|
+
const rawResult = MotelyWasm.analyzeJamlSeeds(jaml, [seed]);
|
|
23
|
+
if (abortController.signal.aborted)
|
|
24
|
+
return;
|
|
25
|
+
if (rawResult && rawResult.seeds.length > 0) {
|
|
26
|
+
const result = rawResult.seeds[0];
|
|
27
|
+
setData(result.analysis || null);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
throw new Error("No analysis result returned");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
if (abortController.signal.aborted)
|
|
35
|
+
return;
|
|
36
|
+
console.error("[useSeedAnalyzer] Analysis error:", err);
|
|
37
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
if (!abortController.signal.aborted)
|
|
41
|
+
setLoading(false);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
runAnalysis();
|
|
45
|
+
return () => abortController.abort();
|
|
46
|
+
}, [seed]);
|
|
47
|
+
return { data, loading, error };
|
|
48
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface CompletionData {
|
|
2
|
+
text: string;
|
|
3
|
+
displayText: string;
|
|
4
|
+
type: 'keyword' | 'value';
|
|
5
|
+
}
|
|
6
|
+
export interface YamlCompletionContext {
|
|
7
|
+
key?: string;
|
|
8
|
+
indent: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class JamlCompletionService {
|
|
11
|
+
static getCompletions(currentValue: string): CompletionData[];
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { JAML_KEYWORDS } from './jamlData';
|
|
2
|
+
export class JamlCompletionService {
|
|
3
|
+
static getCompletions(currentValue) {
|
|
4
|
+
const lower = currentValue.toLowerCase();
|
|
5
|
+
return JAML_KEYWORDS
|
|
6
|
+
.filter(k => k.toLowerCase().includes(lower))
|
|
7
|
+
.map(k => ({
|
|
8
|
+
text: k,
|
|
9
|
+
displayText: k,
|
|
10
|
+
type: 'keyword'
|
|
11
|
+
}));
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const CLAUSE_TYPES = [
|
|
2
|
+
'joker', 'soulJoker', 'voucher', 'tarotCard', 'planetCard',
|
|
3
|
+
'spectralCard', 'standardCard', 'tag', 'boss', 'event'
|
|
4
|
+
];
|
|
5
|
+
export const ARRAY_KEYS = ['antes', 'tags', 'labels'];
|
|
6
|
+
export const JAML_KEYWORDS = [
|
|
7
|
+
'must', 'should', 'mustNot', 'any', 'Any', ...CLAUSE_TYPES, ...ARRAY_KEYS
|
|
8
|
+
];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JAML Objectives Parser
|
|
3
|
+
*
|
|
4
|
+
* Extracts display-ready objective names from a JAML config string
|
|
5
|
+
* using the existing useJamlFilter parser — no hand-rolled regex.
|
|
6
|
+
*
|
|
7
|
+
* This is the ONLY place JAML → objective extraction should happen.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Parse a JAML config string and extract objectives (must-clause values).
|
|
11
|
+
* Returns an array of human-readable objective names.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseJamlToObjectives(jamlConfig: string): string[];
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JAML Objectives Parser
|
|
3
|
+
*
|
|
4
|
+
* Extracts display-ready objective names from a JAML config string
|
|
5
|
+
* using the existing useJamlFilter parser — no hand-rolled regex.
|
|
6
|
+
*
|
|
7
|
+
* This is the ONLY place JAML → objective extraction should happen.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Parse a JAML config string and extract objectives (must-clause values).
|
|
11
|
+
* Returns an array of human-readable objective names.
|
|
12
|
+
*/
|
|
13
|
+
export function parseJamlToObjectives(jamlConfig) {
|
|
14
|
+
if (!jamlConfig.trim())
|
|
15
|
+
return [];
|
|
16
|
+
const objectives = [];
|
|
17
|
+
const lines = jamlConfig.split('\n');
|
|
18
|
+
let inMustBlock = false;
|
|
19
|
+
let currentClause = null;
|
|
20
|
+
for (const line of lines) {
|
|
21
|
+
const trimmed = line.trim();
|
|
22
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
23
|
+
continue;
|
|
24
|
+
// Section headers
|
|
25
|
+
if (trimmed === 'must:') {
|
|
26
|
+
inMustBlock = true;
|
|
27
|
+
currentClause = null;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (trimmed === 'should:' || trimmed === 'mustNot:' || trimmed === 'defaults:') {
|
|
31
|
+
// Flush current clause before leaving must block
|
|
32
|
+
if (inMustBlock && currentClause) {
|
|
33
|
+
const name = currentClause.label || currentClause.value;
|
|
34
|
+
if (name)
|
|
35
|
+
objectives.push(name);
|
|
36
|
+
}
|
|
37
|
+
inMustBlock = false;
|
|
38
|
+
currentClause = null;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (!inMustBlock)
|
|
42
|
+
continue;
|
|
43
|
+
// New clause (starts with -)
|
|
44
|
+
if (trimmed.startsWith('-')) {
|
|
45
|
+
// Flush previous clause
|
|
46
|
+
if (currentClause) {
|
|
47
|
+
const name = currentClause.label || currentClause.value;
|
|
48
|
+
if (name)
|
|
49
|
+
objectives.push(name);
|
|
50
|
+
}
|
|
51
|
+
currentClause = {};
|
|
52
|
+
// Parse inline key:value on same line as dash
|
|
53
|
+
const inlineMatch = trimmed.match(/^-\s*(\w+):\s*(.+)$/);
|
|
54
|
+
if (inlineMatch) {
|
|
55
|
+
const [, key, val] = inlineMatch;
|
|
56
|
+
if (key === 'type')
|
|
57
|
+
currentClause.type = val.trim();
|
|
58
|
+
else if (key === 'value')
|
|
59
|
+
currentClause.value = val.trim();
|
|
60
|
+
else if (key === 'label')
|
|
61
|
+
currentClause.label = val.trim();
|
|
62
|
+
else {
|
|
63
|
+
// Shorthand: `- joker: Blueprint` means type=joker, value=Blueprint
|
|
64
|
+
currentClause.type = key;
|
|
65
|
+
currentClause.value = val.trim();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
// Properties of current clause (indented, no dash)
|
|
71
|
+
if (currentClause) {
|
|
72
|
+
const propMatch = trimmed.match(/^(\w+):\s*(.+)$/);
|
|
73
|
+
if (propMatch) {
|
|
74
|
+
const [, key, val] = propMatch;
|
|
75
|
+
if (key === 'value')
|
|
76
|
+
currentClause.value = val.trim();
|
|
77
|
+
else if (key === 'label')
|
|
78
|
+
currentClause.label = val.trim();
|
|
79
|
+
else if (key === 'type')
|
|
80
|
+
currentClause.type = val.trim();
|
|
81
|
+
else if (!currentClause.value && key !== 'antes' && key !== 'score' && key !== 'sources' && key !== 'edition' && key !== 'seal' && key !== 'enhancement') {
|
|
82
|
+
// Shorthand values like `joker: Blueprint` inside a clause
|
|
83
|
+
// Only use as value if we don't already have one
|
|
84
|
+
currentClause.type = currentClause.type || key;
|
|
85
|
+
currentClause.value = val.trim();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Flush final clause
|
|
91
|
+
if (inMustBlock && currentClause) {
|
|
92
|
+
const name = currentClause.label || currentClause.value;
|
|
93
|
+
if (name)
|
|
94
|
+
objectives.push(name);
|
|
95
|
+
}
|
|
96
|
+
return objectives;
|
|
97
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface HighlightingRules {
|
|
2
|
+
highPriority: Set<string>;
|
|
3
|
+
mediumPriority: Set<string>;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Simple regex-based JAML parser for extracting highlighting rules.
|
|
7
|
+
* Handles basic YAML structure:
|
|
8
|
+
* Must:
|
|
9
|
+
* - joker: WeeJoker
|
|
10
|
+
* Should:
|
|
11
|
+
* - joker: HangingChad
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseJamlHighlights(jamlContent: string | null): HighlightingRules;
|
|
14
|
+
export declare function normalizeName(name: string): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple regex-based JAML parser for extracting highlighting rules.
|
|
3
|
+
* Handles basic YAML structure:
|
|
4
|
+
* Must:
|
|
5
|
+
* - joker: WeeJoker
|
|
6
|
+
* Should:
|
|
7
|
+
* - joker: HangingChad
|
|
8
|
+
*/
|
|
9
|
+
export function parseJamlHighlights(jamlContent) {
|
|
10
|
+
const rules = {
|
|
11
|
+
highPriority: new Set(),
|
|
12
|
+
mediumPriority: new Set()
|
|
13
|
+
};
|
|
14
|
+
if (!jamlContent)
|
|
15
|
+
return rules;
|
|
16
|
+
const lines = jamlContent.split('\n');
|
|
17
|
+
let currentSection = null;
|
|
18
|
+
for (const line of lines) {
|
|
19
|
+
const trimmed = line.trim();
|
|
20
|
+
if (trimmed.startsWith('Must:')) {
|
|
21
|
+
currentSection = 'Must';
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (trimmed.startsWith('Should:')) {
|
|
25
|
+
currentSection = 'Should';
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
// Look for "- joker: Name" or "- souljoker: Name"
|
|
29
|
+
const jokerMatch = trimmed.match(/- (?:joker|souljoker): (.+)/);
|
|
30
|
+
if (jokerMatch) {
|
|
31
|
+
const name = jokerMatch[1].trim();
|
|
32
|
+
// Normalize: "WeeJoker" -> "Wee Joker" if needed?
|
|
33
|
+
// Blueprint output usually has spaces "Wee Joker".
|
|
34
|
+
// JAML uses "WeeJoker".
|
|
35
|
+
// We'll normalize by removing spaces for comparison.
|
|
36
|
+
const normalized = name.replace(/\s+/g, '').toLowerCase();
|
|
37
|
+
if (currentSection === 'Must')
|
|
38
|
+
rules.highPriority.add(normalized);
|
|
39
|
+
if (currentSection === 'Should')
|
|
40
|
+
rules.mediumPriority.add(normalized);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return rules;
|
|
44
|
+
}
|
|
45
|
+
export function normalizeName(name) {
|
|
46
|
+
return name.replace(/\s+/g, '').toLowerCase();
|
|
47
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export const JAML_PRESETS = [
|
|
2
|
+
{
|
|
3
|
+
id: 'soul-hunter',
|
|
4
|
+
label: 'Soul Hunter',
|
|
5
|
+
description: 'Find a Spectral Soul card in early Antes.',
|
|
6
|
+
jaml: `# The Soul Hunter
|
|
7
|
+
name: Soul Hunter
|
|
8
|
+
deck: Red
|
|
9
|
+
stake: White
|
|
10
|
+
|
|
11
|
+
must:
|
|
12
|
+
- spectralCard: The Soul
|
|
13
|
+
antes: [1, 2, 3]
|
|
14
|
+
`
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: 'negative-blueprint',
|
|
18
|
+
label: 'Negative Blueprint',
|
|
19
|
+
description: 'Find a Negative Blueprint early.',
|
|
20
|
+
jaml: `# Negative Blueprint
|
|
21
|
+
name: Negative Blueprint
|
|
22
|
+
deck: Red
|
|
23
|
+
stake: White
|
|
24
|
+
|
|
25
|
+
must:
|
|
26
|
+
- joker: Blueprint
|
|
27
|
+
edition: Negative
|
|
28
|
+
antes: [1, 2, 3, 4]
|
|
29
|
+
`
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'mega-tags',
|
|
33
|
+
label: 'Mega Tags',
|
|
34
|
+
description: 'Find a lot of Investment and Double Tags.',
|
|
35
|
+
jaml: `# Mega Tags
|
|
36
|
+
name: Mega Tags
|
|
37
|
+
deck: Red
|
|
38
|
+
stake: White
|
|
39
|
+
|
|
40
|
+
must:
|
|
41
|
+
- tag: Double Tag
|
|
42
|
+
antes: [1, 2]
|
|
43
|
+
- tag: Investment Tag
|
|
44
|
+
antes: [1, 2]
|
|
45
|
+
`
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'black-hole',
|
|
49
|
+
label: 'Black Hole',
|
|
50
|
+
description: 'Find the elusive Black Hole spectral card.',
|
|
51
|
+
jaml: `# Black Hole
|
|
52
|
+
name: Black Hole
|
|
53
|
+
deck: Red
|
|
54
|
+
stake: White
|
|
55
|
+
|
|
56
|
+
must:
|
|
57
|
+
- spectralCard: Black Hole
|
|
58
|
+
antes: [1, 2, 3, 4]
|
|
59
|
+
`
|
|
60
|
+
}
|
|
61
|
+
];
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JAML Schema Bridge
|
|
3
|
+
*
|
|
4
|
+
* Derives all JAML schema constants from motely-wasm/jaml.schema.json.
|
|
5
|
+
* All JAML-aware files import from here — single swap point if the API changes.
|
|
6
|
+
*/
|
|
7
|
+
export declare const JAML_SCHEMA_VERSION: string;
|
|
8
|
+
/** The raw JSON schema object. */
|
|
9
|
+
export declare const jamlSchema: any;
|
|
10
|
+
/** Root-level metadata keys (name, author, deck, etc.) */
|
|
11
|
+
export declare const METADATA_KEYS: readonly string[];
|
|
12
|
+
/** Section keys that contain clause arrays. */
|
|
13
|
+
export declare const SECTION_KEYS: readonly string[];
|
|
14
|
+
/** Clause type keys — the primary discriminators (joker, voucher, tarot, etc.). */
|
|
15
|
+
export declare const CLAUSE_TYPE_KEYS: readonly string[];
|
|
16
|
+
/** Property keys available inside a clause. */
|
|
17
|
+
export declare const PROPERTY_KEYS: readonly string[];
|
|
18
|
+
/** Source-configuration keys (shopItems, boosterPacks, etc.). */
|
|
19
|
+
export declare const SOURCE_KEYS: readonly string[];
|
|
20
|
+
/**
|
|
21
|
+
* Get the valid enum values for a given JAML key.
|
|
22
|
+
* Checks top-level properties first, then falls back to clause properties.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getValidValuesForKey(key: string): readonly string[] | null;
|
|
25
|
+
/**
|
|
26
|
+
* Get the available properties for a given clause type.
|
|
27
|
+
* Returns all clause property keys (the type system doesn't restrict per-type in JSON schema v7).
|
|
28
|
+
*/
|
|
29
|
+
export declare function getAvailablePropsForType(_clauseType: string): readonly string[];
|
|
30
|
+
/**
|
|
31
|
+
* Check if a property is invalid for a clause type.
|
|
32
|
+
* In the v7 schema, all properties are available on all clause types.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isInvalidPropForType(_prop: string, _clauseType: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Check if a value is invalid for a property.
|
|
37
|
+
*/
|
|
38
|
+
export declare function isInvalidValueForProp(value: string, prop: string): boolean;
|
|
39
|
+
export interface ValidationState {
|
|
40
|
+
errors: string[];
|
|
41
|
+
warnings: string[];
|
|
42
|
+
}
|
|
43
|
+
export declare const DECK_VALUES: readonly string[];
|
|
44
|
+
export declare const STAKE_VALUES: readonly string[];
|
|
45
|
+
export declare const EDITION_VALUES: readonly string[];
|
|
46
|
+
export declare const SEAL_VALUES: readonly string[];
|
|
47
|
+
export declare const ENHANCEMENT_VALUES: readonly string[];
|
|
48
|
+
export declare const RANK_VALUES: readonly string[];
|
|
49
|
+
export declare const SUIT_VALUES: readonly string[];
|
|
50
|
+
export declare const STICKER_VALUES: readonly string[];
|
|
51
|
+
/**
|
|
52
|
+
* All JAML keywords — sections, metadata keys, clause types, and property keys.
|
|
53
|
+
*/
|
|
54
|
+
export declare const ALL_JAML_KEYWORDS: string[];
|