intelligent-system-design-language 0.4.0 → 0.4.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/out/cli/cli-util.js +9 -3
- package/out/cli/cli-util.js.map +1 -1
- package/out/cli/components/derived-data-generator.js +23 -8
- package/out/cli/components/derived-data-generator.js.map +1 -1
- package/out/cli/components/dev-module-generator.js +399 -0
- package/out/cli/components/dev-module-generator.js.map +1 -0
- package/out/cli/components/method-generator.js +83 -36
- package/out/cli/components/method-generator.js.map +1 -1
- package/out/cli/components/vue/base-components/vue-string-choices.js +11 -4
- package/out/cli/components/vue/base-components/vue-string-choices.js.map +1 -1
- package/out/cli/generator.js +46 -42
- package/out/cli/generator.js.map +1 -1
- package/out/extension/main.cjs +710 -560
- package/out/extension/main.cjs.map +4 -4
- package/out/extension/main.js +2 -2
- package/out/extension/main.js.map +1 -1
- package/out/extension/package.json +1 -1
- package/out/language/generated/ast.js +13 -4
- package/out/language/generated/ast.js.map +1 -1
- package/out/language/generated/grammar.js +106 -32
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/intelligent-system-design-language-module.js +3 -1
- package/out/language/intelligent-system-design-language-module.js.map +1 -1
- package/out/language/intelligent-system-design-language-validator.js +20 -7
- package/out/language/intelligent-system-design-language-validator.js.map +1 -1
- package/out/language/isdl-completion-provider.js +32 -0
- package/out/language/isdl-completion-provider.js.map +1 -0
- package/out/language/isdl-docs.js +106 -0
- package/out/language/isdl-docs.js.map +1 -0
- package/out/language/isdl-hover-provider.js +4 -54
- package/out/language/isdl-hover-provider.js.map +1 -1
- package/out/language/main.cjs +633 -483
- package/out/language/main.cjs.map +4 -4
- package/out/package.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import { expandToNode, toString } from 'langium/generate';
|
|
4
|
+
import { isConfigExpression, isActor, isItem } from '../../language/generated/ast.js';
|
|
5
|
+
export function generateDevModule(entry, id, devDest) {
|
|
6
|
+
var _a, _b, _c, _d;
|
|
7
|
+
const scriptsDir = path.join(devDest, 'scripts');
|
|
8
|
+
if (!fs.existsSync(scriptsDir)) {
|
|
9
|
+
fs.mkdirSync(scriptsDir, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
const title = (_b = (_a = entry.config.body.find(x => isConfigExpression(x) && x.type === 'label')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : id;
|
|
12
|
+
const author = (_d = (_c = entry.config.body.find(x => isConfigExpression(x) && x.type === 'author')) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '';
|
|
13
|
+
// Foundry fires `render${ClassName}` — for our generated sheets that's `render<Doc>VueSheet`
|
|
14
|
+
// (e.g. renderHeroVueSheet), NOT the generic renderActorSheet. Hook the real class names so
|
|
15
|
+
// the dev overlays actually attach.
|
|
16
|
+
const sheetHooks = entry.documents
|
|
17
|
+
.filter(d => isActor(d) || isItem(d))
|
|
18
|
+
.map(d => `render${d.name}VueSheet`);
|
|
19
|
+
generateModuleJson(id, title, author, devDest);
|
|
20
|
+
generateDevTools(id, title, devDest, sheetHooks);
|
|
21
|
+
}
|
|
22
|
+
function generateModuleJson(id, title, author, devDest) {
|
|
23
|
+
const filePath = path.join(devDest, 'module.json');
|
|
24
|
+
const fileNode = expandToNode `
|
|
25
|
+
{
|
|
26
|
+
"id": "${id}-dev",
|
|
27
|
+
"title": "${title} — Dev Tools",
|
|
28
|
+
"description": "Developer companion module for ${title}. Install locally; never distribute to players.",
|
|
29
|
+
"version": "dev",
|
|
30
|
+
"compatibility": {
|
|
31
|
+
"minimum": 12,
|
|
32
|
+
"verified": 14
|
|
33
|
+
},
|
|
34
|
+
"authors": [
|
|
35
|
+
{ "name": "${author}" }
|
|
36
|
+
],
|
|
37
|
+
"esmodules": [
|
|
38
|
+
"scripts/dev-tools.mjs"
|
|
39
|
+
],
|
|
40
|
+
"relationships": {
|
|
41
|
+
"systems": [
|
|
42
|
+
{
|
|
43
|
+
"id": "${id}",
|
|
44
|
+
"type": "system",
|
|
45
|
+
"reason": "Dev tools require the ${title} system to be active"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
`.appendNewLineIfNotEmpty();
|
|
51
|
+
fs.writeFileSync(filePath, toString(fileNode));
|
|
52
|
+
}
|
|
53
|
+
function generateDevTools(id, title, devDest, sheetHooks) {
|
|
54
|
+
const filePath = path.join(devDest, 'scripts', 'dev-tools.mjs');
|
|
55
|
+
const allRenderHooks = ['renderActorSheet', 'renderActorSheetV2', 'renderItemSheet', 'renderItemSheetV2', ...sheetHooks];
|
|
56
|
+
const fileNode = expandToNode `
|
|
57
|
+
// ${id}-dev — developer companion for ${title}
|
|
58
|
+
// Regenerated on each build. Customise ${id}-custom.mjs instead.
|
|
59
|
+
|
|
60
|
+
const MODULE_ID = "${id}-dev";
|
|
61
|
+
|
|
62
|
+
// ─── Vue DevTools ───────────────────────────────────────────────────
|
|
63
|
+
// Only enable if the Vue DevTools extension is already installed —
|
|
64
|
+
// creating a stub hook causes Vue to call emit() on a no-op object and break.
|
|
65
|
+
if (window.__VUE_DEVTOOLS_GLOBAL_HOOK__) {
|
|
66
|
+
window.__VUE_DEVTOOLS_GLOBAL_HOOK__.enabled = true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ─── Tooltip styles ─────────────────────────────────────────────────
|
|
70
|
+
{
|
|
71
|
+
const style = document.createElement("style");
|
|
72
|
+
style.textContent = \`
|
|
73
|
+
.isdl-dev-tooltip {
|
|
74
|
+
position: fixed;
|
|
75
|
+
background: #1a1a2e;
|
|
76
|
+
border: 1px solid #4a9eff;
|
|
77
|
+
border-radius: 4px;
|
|
78
|
+
padding: 6px 8px;
|
|
79
|
+
font-family: monospace;
|
|
80
|
+
font-size: 11px;
|
|
81
|
+
color: #e0e0e0;
|
|
82
|
+
box-shadow: 0 2px 8px rgba(0,0,0,.6);
|
|
83
|
+
pointer-events: none;
|
|
84
|
+
min-width: 220px;
|
|
85
|
+
z-index: 10000;
|
|
86
|
+
}
|
|
87
|
+
.isdl-dev-section-header {
|
|
88
|
+
font-size: 10px;
|
|
89
|
+
font-weight: bold;
|
|
90
|
+
color: #c0d8f0;
|
|
91
|
+
border-bottom: 1px solid #2a3a5a;
|
|
92
|
+
padding-bottom: 3px;
|
|
93
|
+
margin-bottom: 4px;
|
|
94
|
+
display: flex;
|
|
95
|
+
align-items: center;
|
|
96
|
+
gap: 5px;
|
|
97
|
+
}
|
|
98
|
+
.isdl-dev-section-hint {
|
|
99
|
+
font-weight: normal;
|
|
100
|
+
font-size: 9px;
|
|
101
|
+
color: #6a8aaa;
|
|
102
|
+
margin-left: auto;
|
|
103
|
+
}
|
|
104
|
+
.isdl-dev-label {
|
|
105
|
+
font-size: 9px;
|
|
106
|
+
text-transform: uppercase;
|
|
107
|
+
letter-spacing: 0.05em;
|
|
108
|
+
color: #6a8aaa;
|
|
109
|
+
margin-top: 5px;
|
|
110
|
+
margin-bottom: 1px;
|
|
111
|
+
}
|
|
112
|
+
.isdl-dev-label:first-child { margin-top: 0; }
|
|
113
|
+
.isdl-dev-row {
|
|
114
|
+
display: flex;
|
|
115
|
+
align-items: center;
|
|
116
|
+
gap: 6px;
|
|
117
|
+
padding: 2px 0;
|
|
118
|
+
}
|
|
119
|
+
.isdl-dev-row i { color: #4a9eff; width: 14px; text-align: center; }
|
|
120
|
+
.isdl-dev-row code { flex: 1; font-size: 10px; color: #a0cfff; word-break: break-all; }
|
|
121
|
+
.isdl-dev-copy {
|
|
122
|
+
background: none;
|
|
123
|
+
border: 1px solid #4a9eff;
|
|
124
|
+
border-radius: 2px;
|
|
125
|
+
color: #4a9eff;
|
|
126
|
+
cursor: pointer;
|
|
127
|
+
padding: 1px 5px;
|
|
128
|
+
font-size: 10px;
|
|
129
|
+
line-height: 1.4;
|
|
130
|
+
}
|
|
131
|
+
.isdl-dev-copy:hover { background: #4a9eff; color: #1a1a2e; }
|
|
132
|
+
.isdl-pick-mode-btn { opacity: 0.4; transition: opacity 0.15s, color 0.15s; }
|
|
133
|
+
.isdl-pick-mode-btn.isdl-pick-active { opacity: 1; color: #f6a623 !important; }
|
|
134
|
+
.isdl-dev-tooltip.isdl-dev-locked { border-color: #f6a623; box-shadow: 0 4px 16px rgba(0,0,0,.8); pointer-events: auto; }
|
|
135
|
+
.isdl-dev-tip-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; padding-bottom: 4px; border-bottom: 1px solid #2a3a5a; }
|
|
136
|
+
.isdl-dev-tip-title { font-size: 10px; font-weight: bold; color: #f6a623; letter-spacing: 0.05em; }
|
|
137
|
+
.isdl-dev-dismiss { background: none; border: 1px solid #f6a623; border-radius: 2px; color: #f6a623; cursor: pointer; padding: 0 5px; font-size: 11px; line-height: 1.6; }
|
|
138
|
+
.isdl-dev-dismiss:hover { background: #f6a623; color: #1a1a2e; }
|
|
139
|
+
.isdl-inspector { display: flex; flex-direction: column; gap: 8px; padding: 4px 0; }
|
|
140
|
+
.isdl-inspector-hint { font-size: 12px; color: #888; margin: 0; }
|
|
141
|
+
.isdl-inspector-hint code { font-size: 11px; background: #eee; padding: 1px 3px; border-radius: 2px; }
|
|
142
|
+
.isdl-inspector-copy-all { align-self: flex-end; cursor: pointer; }
|
|
143
|
+
.isdl-inspector-pre {
|
|
144
|
+
max-height: 420px;
|
|
145
|
+
overflow: auto;
|
|
146
|
+
font-size: 11px;
|
|
147
|
+
font-family: monospace;
|
|
148
|
+
background: #1a1a2e;
|
|
149
|
+
color: #a0cfff;
|
|
150
|
+
padding: 10px;
|
|
151
|
+
border-radius: 4px;
|
|
152
|
+
margin: 0;
|
|
153
|
+
white-space: pre;
|
|
154
|
+
line-height: 1.5;
|
|
155
|
+
}
|
|
156
|
+
\`;
|
|
157
|
+
document.head.appendChild(style);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ─── Pick-mode field inspector ──────────────────────────────────────
|
|
161
|
+
let _pickMode = false;
|
|
162
|
+
let _hoverTip = null;
|
|
163
|
+
let _lockedTip = null;
|
|
164
|
+
|
|
165
|
+
function _setPickMode(enabled) {
|
|
166
|
+
_pickMode = enabled;
|
|
167
|
+
if (!enabled) { _clearLockedTip(); _clearHoverTip(); }
|
|
168
|
+
document.querySelectorAll(".isdl-pick-mode-btn")
|
|
169
|
+
.forEach(b => b.classList.toggle("isdl-pick-active", enabled));
|
|
170
|
+
console.log(\`[\${MODULE_ID}] pick mode \${enabled ? "ON — hover a field, click to lock" : "off"}\`);
|
|
171
|
+
}
|
|
172
|
+
function _clearHoverTip() { _hoverTip?.remove(); _hoverTip = null; }
|
|
173
|
+
function _clearLockedTip() { _lockedTip?.remove(); _lockedTip = null; }
|
|
174
|
+
|
|
175
|
+
function _makeRow(iconClass, label, value) {
|
|
176
|
+
return \`
|
|
177
|
+
<div class="isdl-dev-label">\${label}</div>
|
|
178
|
+
<div class="isdl-dev-row">
|
|
179
|
+
<i class="\${iconClass}"></i>
|
|
180
|
+
<code>\${value}</code>
|
|
181
|
+
<button type="button" class="isdl-dev-copy" data-copy="\${value}" title="Copy">
|
|
182
|
+
<i class="fa-solid fa-copy"></i>
|
|
183
|
+
</button>
|
|
184
|
+
</div>
|
|
185
|
+
\`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function _buildTipBody(systemPath, typeSelector, nameSelector) {
|
|
189
|
+
return \`<div class="isdl-dev-section-header"><i class="fa-solid fa-database"></i> Data Path<span class="isdl-dev-section-hint">for macros & scripts</span></div>\`
|
|
190
|
+
+ _makeRow("fa-solid fa-folder-open", "system path", systemPath)
|
|
191
|
+
+ \`<div class="isdl-dev-section-header" style="margin-top:8px"><i class="fa-solid fa-paintbrush"></i> CSS Selectors<span class="isdl-dev-section-hint">for custom.css</span></div>\`
|
|
192
|
+
+ (typeSelector ? _makeRow("fa-solid fa-layer-group", "all fields of this type", typeSelector) : "")
|
|
193
|
+
+ (nameSelector ? _makeRow("fa-solid fa-crosshairs", "just this field", nameSelector) : "");
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function _positionTip(tip, el) {
|
|
197
|
+
const rect = el.getBoundingClientRect();
|
|
198
|
+
tip.style.top = (rect.bottom + 4) + "px";
|
|
199
|
+
tip.style.left = rect.left + "px";
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function _showHoverTip(el, systemPath, typeSelector, nameSelector) {
|
|
203
|
+
_clearHoverTip();
|
|
204
|
+
if (!_pickMode || _lockedTip) return;
|
|
205
|
+
const tip = document.createElement("div");
|
|
206
|
+
tip.className = "isdl-dev-tooltip";
|
|
207
|
+
tip.innerHTML = _buildTipBody(systemPath, typeSelector, nameSelector);
|
|
208
|
+
_positionTip(tip, el);
|
|
209
|
+
document.body.appendChild(tip);
|
|
210
|
+
_hoverTip = tip;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function _lockTip(el, systemPath, typeSelector, nameSelector) {
|
|
214
|
+
_clearHoverTip();
|
|
215
|
+
_clearLockedTip();
|
|
216
|
+
const tip = document.createElement("div");
|
|
217
|
+
tip.className = "isdl-dev-tooltip isdl-dev-locked";
|
|
218
|
+
tip.innerHTML =
|
|
219
|
+
\`<div class="isdl-dev-tip-header"><span class="isdl-dev-tip-title"><i class="fa-solid fa-crosshairs"></i> FIELD INFO</span><button type="button" class="isdl-dev-dismiss" title="Dismiss">×</button></div>\`
|
|
220
|
+
+ _buildTipBody(systemPath, typeSelector, nameSelector);
|
|
221
|
+
tip.querySelector(".isdl-dev-dismiss").addEventListener("click", e => { e.stopPropagation(); _clearLockedTip(); });
|
|
222
|
+
tip.querySelectorAll(".isdl-dev-copy").forEach(btn => {
|
|
223
|
+
btn.addEventListener("click", e => {
|
|
224
|
+
e.stopPropagation();
|
|
225
|
+
navigator.clipboard.writeText(btn.dataset.copy).then(() => {
|
|
226
|
+
const icon = btn.querySelector("i");
|
|
227
|
+
icon.className = "fa-solid fa-check";
|
|
228
|
+
setTimeout(() => icon.className = "fa-solid fa-copy", 1500);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
_positionTip(tip, el);
|
|
233
|
+
document.body.appendChild(tip);
|
|
234
|
+
_lockedTip = tip;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Delegated field listeners — attached once on document, so they work for Vue-mounted
|
|
238
|
+
// fields regardless of render timing and survive sheet re-renders.
|
|
239
|
+
let _pickWired = false;
|
|
240
|
+
function _wirePickDelegation() {
|
|
241
|
+
if (_pickWired) return;
|
|
242
|
+
_pickWired = true;
|
|
243
|
+
let _curField = null;
|
|
244
|
+
const _fieldAt = t => {
|
|
245
|
+
const el = t?.closest?.("[class*='isdl-']");
|
|
246
|
+
if (!el) return null;
|
|
247
|
+
const input = el.querySelector("input[name^='system.'], select[name^='system.'], textarea[name^='system.']");
|
|
248
|
+
if (!input) return null;
|
|
249
|
+
const { typeSelector, nameSelector } = _buildCssSelectors(el);
|
|
250
|
+
return { el, systemPath: input.getAttribute("name"), typeSelector, nameSelector };
|
|
251
|
+
};
|
|
252
|
+
document.addEventListener("mouseover", e => {
|
|
253
|
+
if (!_pickMode) return;
|
|
254
|
+
const f = _fieldAt(e.target);
|
|
255
|
+
if (f && f.el !== _curField) { _curField = f.el; _showHoverTip(f.el, f.systemPath, f.typeSelector, f.nameSelector); }
|
|
256
|
+
else if (!f && _curField) { _curField = null; _clearHoverTip(); }
|
|
257
|
+
});
|
|
258
|
+
document.addEventListener("click", e => {
|
|
259
|
+
if (!_pickMode) return;
|
|
260
|
+
const f = _fieldAt(e.target);
|
|
261
|
+
if (f) { e.stopPropagation(); _lockTip(f.el, f.systemPath, f.typeSelector, f.nameSelector); }
|
|
262
|
+
}, true);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function _buildCssSelectors(el) {
|
|
266
|
+
const classes = [...el.classList];
|
|
267
|
+
// e.g. isdl-field-brawn → "Just this field"
|
|
268
|
+
const nameClass = classes.find(c => /^isdl-field-[a-z]/.test(c));
|
|
269
|
+
// e.g. isdl-number, isdl-attribute — the field type, skip field/visibility/name classes
|
|
270
|
+
const typeClass = classes.find(c =>
|
|
271
|
+
c.startsWith("isdl-") &&
|
|
272
|
+
c !== "isdl-field" &&
|
|
273
|
+
!c.startsWith("isdl-visibility-") &&
|
|
274
|
+
!c.startsWith("isdl-field-")
|
|
275
|
+
);
|
|
276
|
+
return {
|
|
277
|
+
typeSelector: typeClass ? \`.\${typeClass}\` : null,
|
|
278
|
+
nameSelector: nameClass ? \`.\${nameClass}\` : null
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ─── System data inspector ──────────────────────────────────────────
|
|
283
|
+
function _openInspector(doc) {
|
|
284
|
+
const data = doc.system?.toObject?.() ?? doc.system ?? {};
|
|
285
|
+
const json = JSON.stringify(data, null, 2);
|
|
286
|
+
new Dialog({
|
|
287
|
+
title: \`System Data — \${doc.name}\`,
|
|
288
|
+
content: \`
|
|
289
|
+
<div class="isdl-inspector">
|
|
290
|
+
<p class="isdl-inspector-hint">
|
|
291
|
+
<i class="fa-solid fa-circle-info"></i>
|
|
292
|
+
Everything stored in <code>actor.system</code> for this document.
|
|
293
|
+
Use these paths in macros, roll formulas, and scripts.
|
|
294
|
+
</p>
|
|
295
|
+
<button type="button" class="isdl-inspector-copy-all">
|
|
296
|
+
<i class="fa-solid fa-copy"></i> Copy all
|
|
297
|
+
</button>
|
|
298
|
+
<pre class="isdl-inspector-pre">\${json}</pre>
|
|
299
|
+
</div>
|
|
300
|
+
\`,
|
|
301
|
+
buttons: { close: { label: "Close" } },
|
|
302
|
+
render: html => {
|
|
303
|
+
const root = html instanceof HTMLElement ? html : html?.[0];
|
|
304
|
+
root?.querySelector(".isdl-inspector-copy-all")?.addEventListener("click", () => {
|
|
305
|
+
navigator.clipboard.writeText(json).then(() => {
|
|
306
|
+
const btn = root.querySelector(".isdl-inspector-copy-all");
|
|
307
|
+
if (btn) {
|
|
308
|
+
btn.innerHTML = \`<i class="fa-solid fa-check"></i> Copied!\`;
|
|
309
|
+
setTimeout(() => { btn.innerHTML = \`<i class="fa-solid fa-copy"></i> Copy all\`; }, 1500);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}).render(true);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// ─── Sheet overlay ──────────────────────────────────────────────────
|
|
318
|
+
function _addHeaderControl(header, btn) {
|
|
319
|
+
const closeBtn = header.querySelector(".close, [data-action='close'], [aria-label='Close']");
|
|
320
|
+
if (closeBtn) closeBtn.before(btn); else header.append(btn);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function _activateOverlays(doc, html) {
|
|
324
|
+
const root = html instanceof HTMLElement ? html : html?.[0];
|
|
325
|
+
if (!root) return;
|
|
326
|
+
|
|
327
|
+
// v14: header is a direct child of the form (root IS the sheet element)
|
|
328
|
+
// v12/v13: header is a sibling of root inside .window-app
|
|
329
|
+
const header = root.querySelector(".window-header, .window-controls")
|
|
330
|
+
?? root.closest(".window-app, .application")?.querySelector(".window-header, .window-controls");
|
|
331
|
+
|
|
332
|
+
// System Data Viewer button — icon as an <i> child (not a class on the button),
|
|
333
|
+
// inserted before the close control so it sits on the right.
|
|
334
|
+
if (header && !header.querySelector(".isdl-inspector-btn")) {
|
|
335
|
+
const btn = document.createElement("button");
|
|
336
|
+
btn.type = "button";
|
|
337
|
+
btn.className = "isdl-inspector-btn header-control";
|
|
338
|
+
btn.innerHTML = '<i class="fa-solid fa-magnifying-glass"></i>';
|
|
339
|
+
btn.setAttribute("aria-label", "Inspect System Data");
|
|
340
|
+
btn.setAttribute("data-tooltip", "Inspect System Data");
|
|
341
|
+
btn.addEventListener("click", e => { e.preventDefault(); _openInspector(doc); });
|
|
342
|
+
_addHeaderControl(header, btn);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Pick Mode button — toggles the field path/CSS picker: hover a field to preview
|
|
346
|
+
// its data path + CSS selectors, click to lock the tooltip.
|
|
347
|
+
if (header && !header.querySelector(".isdl-pick-mode-btn")) {
|
|
348
|
+
const btn = document.createElement("button");
|
|
349
|
+
btn.type = "button";
|
|
350
|
+
btn.className = "isdl-pick-mode-btn header-control";
|
|
351
|
+
btn.innerHTML = '<i class="fa-solid fa-crosshairs"></i>';
|
|
352
|
+
btn.setAttribute("aria-label", "Pick Mode");
|
|
353
|
+
btn.setAttribute("data-tooltip", "Pick Mode — hover a field to preview its data path & CSS, click to lock the tooltip");
|
|
354
|
+
btn.addEventListener("click", e => { e.preventDefault(); _setPickMode(!_pickMode); });
|
|
355
|
+
_addHeaderControl(header, btn);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Field hover/click is handled by a single delegated listener (wired once below),
|
|
359
|
+
// so it works for Vue-mounted fields regardless of render timing.
|
|
360
|
+
_wirePickDelegation();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// ─── Verbose logging ────────────────────────────────────────────────
|
|
364
|
+
Hooks.once("init", () => {
|
|
365
|
+
console.group(\`[\${MODULE_ID}] init\`);
|
|
366
|
+
console.log("system:", game.system);
|
|
367
|
+
console.groupEnd();
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
Hooks.once("ready", () => {
|
|
371
|
+
console.group(\`[\${MODULE_ID}] ready\`);
|
|
372
|
+
console.log("actors:", game.actors?.size ?? 0);
|
|
373
|
+
console.log("items:", game.items?.size ?? 0);
|
|
374
|
+
console.groupEnd();
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// ApplicationV2 (Foundry v13+) fires renderActorSheetV2 / renderItemSheetV2
|
|
378
|
+
// ApplicationV1 fires the legacy renderActorSheet / renderItemSheet
|
|
379
|
+
// Foundry fires render<ClassName>; our sheets are <Doc>VueSheet. The generic
|
|
380
|
+
// ActorSheet/ItemSheet names are kept as a fallback for other Foundry versions.
|
|
381
|
+
for (const hook of ${JSON.stringify(allRenderHooks)}) {
|
|
382
|
+
Hooks.on(hook, (app, html) => {
|
|
383
|
+
const doc = app.actor ?? app.item ?? app.document;
|
|
384
|
+
_activateOverlays(doc, html instanceof HTMLElement ? html : html?.[0] ?? app.element);
|
|
385
|
+
console.log(\`[\${MODULE_ID}] \${hook}\`, doc?.name);
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
Hooks.on("preUpdateActor", (actor, changes) => {
|
|
390
|
+
console.log(\`[\${MODULE_ID}] preUpdateActor\`, actor.name, changes);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
Hooks.on("preUpdateItem", (item, changes) => {
|
|
394
|
+
console.log(\`[\${MODULE_ID}] preUpdateItem\`, item.name, changes);
|
|
395
|
+
});
|
|
396
|
+
`.appendNewLineIfNotEmpty();
|
|
397
|
+
fs.writeFileSync(filePath, toString(fileNode));
|
|
398
|
+
}
|
|
399
|
+
//# sourceMappingURL=dev-module-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-module-generator.js","sourceRoot":"","sources":["../../../src/cli/components/dev-module-generator.ts"],"names":[],"mappings":"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"}
|