@lotics/cli 0.196.0 → 0.198.0
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 +34 -9
- package/dist/probe_page.js +162 -24
- package/dist/render_page.js +152 -41
- package/dist/src/cli.js +5535 -937
- package/dist/src/client.d.ts +123 -24
- package/dist/src/client.js +64 -3
- package/docs/building_an_app.md +30 -4
- package/docs/cli_reference.md +20 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -92,6 +92,12 @@ It creates no apps of its own: build one in the workspace afterwards
|
|
|
92
92
|
copied in — bound onto the tables the model just made — as part of the same run.
|
|
93
93
|
`setup` refuses a table name your workspace already has; `lotics scaffold apply model.json` is the
|
|
94
94
|
additive verb — it adopts that table, adds what the model declares beyond it, and deletes nothing.
|
|
95
|
+
Because it never renames, the file and the workspace drift: `lotics scaffold diff model.json`
|
|
96
|
+
prints exactly where and exits non-zero on any difference, and
|
|
97
|
+
`lotics field rename <table> <field> "<new label>"` moves a label on the platform, in the file
|
|
98
|
+
(`--model`) and in every app bound to it (`--apps`) at once. `lotics scaffold apply model.json
|
|
99
|
+
--documents` writes only the file cells of the model's rows, onto the records the first run made —
|
|
100
|
+
rows land only into empty tables, so it is the one way back for attachments that were missed.
|
|
95
101
|
|
|
96
102
|
The other direction, once a workspace works: `lotics scaffold export > model.json` prints its
|
|
97
103
|
tables (or only `--tables tbl_a,tbl_b`) as that same file, findings on stderr. It is a starting
|
|
@@ -177,7 +183,7 @@ lotics workspace select wks_... # records the workspace in the local pin
|
|
|
177
183
|
|
|
178
184
|
Each worktree resolves independently; switching the global default in another shell leaves pinned worktrees untouched. `.lotics/` should be gitignored.
|
|
179
185
|
|
|
180
|
-
Every command that resolves a workspace names its target before it acts — `lotics →
|
|
186
|
+
Every command that resolves a workspace names its target before it acts — `lotics → Starters / Equipment & Projects` on **stderr**, so stdout stays clean for piping. Both halves are NAMES, since the line exists to be read before a destructive write; the workspace's name is cached beside its id the first time any command lists it, and until then the line prints the id and says the name is not known yet. When nothing in the directory or environment chose the org and it came from the machine-wide default, the line says so and prints the `--local` command to pin — that default is the one another shell can move between two of your commands. `lotics auth whoami` reports the same resolution on demand, including which source won.
|
|
181
187
|
|
|
182
188
|
### Resolution precedence
|
|
183
189
|
|
|
@@ -189,6 +195,8 @@ Every command that resolves a workspace names its target before it acts — `lot
|
|
|
189
195
|
|
|
190
196
|
`LOTICS_WORKSPACE` (or `--workspace <id>` / `-w`) overrides the workspace at any level. For ephemeral or CI use, set `LOTICS_API_KEY` instead of saving anything.
|
|
191
197
|
|
|
198
|
+
**`LOTICS_ORG` is resolved once, before any command runs.** A value matching no saved credential refuses every verb with one sentence — a read, a write, and a check that needs no credential alike — and the refusal lists the orgs this machine does hold, so it is answerable without another command. It refuses even when a key arrives another way: a variable that scopes the command must not go unread while `LOTICS_API_KEY` sends the write somewhere else. When the variable resolves AND a key is supplied, the key decides the org and the command says so. A server-side rename leaves the cached org name stale, so name an org by its `org_` id when a concurrent session may rename it.
|
|
199
|
+
|
|
192
200
|
### Diagnostics
|
|
193
201
|
|
|
194
202
|
Every request identifies the CLI (`user-agent: lotics-cli/<version> node/<v> <platform>`) and names the command that made it (`x-lotics-cli-command: app.workflow.set`), so a failure in the server's logs can be traced to the verb and version that produced it. Neither header carries arguments: the command chain stops before any id, path, `@file`, or JSON payload.
|
|
@@ -248,7 +256,11 @@ Workspaces live inside the active org. If the org has more than one, select befo
|
|
|
248
256
|
```bash
|
|
249
257
|
lotics workspace # list workspaces in the active org (marks current)
|
|
250
258
|
lotics workspace select wks_... # set the workspace for the active scope (pin or profile)
|
|
251
|
-
lotics workspace create "Sales"
|
|
259
|
+
lotics workspace create "Sales" --timezone America/New_York --currency USD
|
|
260
|
+
# create a new workspace (admin only); without the flags it
|
|
261
|
+
# takes the org's oldest workspace's zone and currency
|
|
262
|
+
lotics workspace settings --currency USD --timezone America/New_York
|
|
263
|
+
# change the current workspace's name/currency/zone
|
|
252
264
|
lotics workspace delete wks_... --yes # delete a workspace (admin only; soft delete, recoverable)
|
|
253
265
|
```
|
|
254
266
|
|
|
@@ -268,8 +280,8 @@ lotics run query_records '{"table_id":"tbl_...","field_keys":["name"]}'
|
|
|
268
280
|
# Large args (a knowledge-doc `content`, a bulk update) exceed the OS arg limit —
|
|
269
281
|
# read them from a file or stdin instead of an inline arg:
|
|
270
282
|
lotics run create_knowledge @args.json
|
|
271
|
-
cat args.json | lotics run create_knowledge
|
|
272
|
-
echo '{"table_id":"tbl_..."}' | lotics run query_records
|
|
283
|
+
cat args.json | lotics run create_knowledge - # the trailing - reads stdin
|
|
284
|
+
echo '{"table_id":"tbl_..."}' | lotics run query_records -
|
|
273
285
|
|
|
274
286
|
# Upload files (multiple files and directories supported)
|
|
275
287
|
lotics upload ./report.pdf ./data.csv ./documents/
|
|
@@ -278,6 +290,10 @@ lotics upload ./report.pdf ./data.csv ./documents/
|
|
|
278
290
|
lotics run generate_excel_from_template '{"..."}'
|
|
279
291
|
lotics download <file_id> -o ./reports/
|
|
280
292
|
|
|
293
|
+
# What is in the store, newest first — one page, with the command for the next one
|
|
294
|
+
lotics file list --limit 50
|
|
295
|
+
lotics file delete <file_id> # refused while anything still references it
|
|
296
|
+
|
|
281
297
|
# CI / non-interactive (key inline)
|
|
282
298
|
LOTICS_API_KEY=ltk_... lotics run query_tables '{}'
|
|
283
299
|
|
|
@@ -345,10 +361,17 @@ lotics app codegen # import { F, OPT } from "../.lotics/
|
|
|
345
361
|
# the code calls that nothing bound, undeclared capabilities, query drift. Exits 1 on what a deploy refuses, so CI can gate on it.
|
|
346
362
|
lotics app check
|
|
347
363
|
|
|
364
|
+
# --screens adds the rendered surface: each screen the app's navigation reaches,
|
|
365
|
+
# and the first record each one opens onto a PAGE, headless in Chrome at 1280
|
|
366
|
+
# and 375, measured against @lotics/ui docs/reviewing.md. --screen and --width
|
|
367
|
+
# narrow it while you iterate on one screen.
|
|
368
|
+
lotics app check --screens
|
|
369
|
+
lotics app check --screens --screen "Đơn hàng" --width 375
|
|
370
|
+
|
|
348
371
|
# Running an app's alias is a TOOL call, like every other tool. Exits non-zero
|
|
349
372
|
# when the RUN failed, not only when the call did.
|
|
350
373
|
lotics run run_app_workflow '{"app_id":"app_...","alias":"issueInvoice","inputs":{"record_id":"rec_..."}}'
|
|
351
|
-
cat args.json | lotics run run_app_workflow
|
|
374
|
+
cat args.json | lotics run run_app_workflow - # bulk inputs bypass ARG_MAX
|
|
352
375
|
# Honest post-run harvest: created records + a paste-ready cleanup plan + the
|
|
353
376
|
# caveat (external/notification calls can't be auto-undone; sub-workflows may run).
|
|
354
377
|
lotics run run_app_workflow '{...}' --print-created
|
|
@@ -357,11 +380,13 @@ lotics run run_app_workflow '{...}' --cleanup # also deletes created records (
|
|
|
357
380
|
# Edit workflow bodies as files. `app pull` writes src/workflows/<alias>.ts (the
|
|
358
381
|
# faithful server source, wrapped + referencing its .lotics/workflows/<alias>.globals.d.ts);
|
|
359
382
|
# edit the body, then push it back through set_app_workflow — the server verifies it
|
|
360
|
-
# (deploy
|
|
383
|
+
# (a deploy calls the same verb for every alias the project holds ahead of the app, so
|
|
384
|
+
# this is the one-alias spelling of it). `app workflow check` runs the server's own
|
|
361
385
|
# JS-subset parser + type-check locally, so a body that passes is one `set` will accept
|
|
362
386
|
# (`set` still adds name resolution + lint + structural checks, which need the workspace):
|
|
363
387
|
lotics app workflow pull # rewrite src/workflows/*.ts + globals from the server
|
|
364
|
-
lotics app workflow check # parse + typecheck every body locally ([alias] for
|
|
388
|
+
lotics app workflow check # parse + typecheck every body locally ([alias...] for some)
|
|
389
|
+
lotics app workflow diff issueInvoice # how the local body differs from the one the server runs
|
|
365
390
|
lotics app workflow set issueInvoice # push the edited src/workflows/issueInvoice.ts
|
|
366
391
|
|
|
367
392
|
# Iterate on a named query WITHOUT a deploy: push package.json#lotics.queries.<alias>
|
|
@@ -373,7 +398,7 @@ lotics app query set openInvoices # push package.json#lotics.queries.o
|
|
|
373
398
|
# + member auth). Streams progress to stderr; reports the SETTLED run (structured
|
|
374
399
|
# output / final text) to stdout; exits 0 only when the run completed.
|
|
375
400
|
lotics run run_app_agent '{"app_id":"app_abc","alias":"recognize","input":{"image_file_id":"fil_..."}}'
|
|
376
|
-
cat input.json | lotics run run_app_agent
|
|
401
|
+
cat input.json | lotics run run_app_agent - # inputs via stdin/@file
|
|
377
402
|
lotics run run_app_agent '{...}' --json # full run summary to stdout
|
|
378
403
|
# A run that outlives the call's bounded wait keeps going server-side; read it with
|
|
379
404
|
lotics run get_app_agent_run '{"app_id":"app_abc","run_id":"run_..."}'
|
|
@@ -385,7 +410,7 @@ LOTICS_UI_SRC=/abs/monorepo/packages/ui/src lotics app deploy -m "..." # warns
|
|
|
385
410
|
lotics app dev # unset ⇒ @lotics/ui resolves from node_modules again
|
|
386
411
|
```
|
|
387
412
|
|
|
388
|
-
`app codegen`
|
|
413
|
+
`app codegen` puts a table in `app_fields.ts` when a declared query reads it or a bound workflow writes it — the queries come from `package.json#lotics.queries`, the written tables from each binding's own `table_ids`, so a table only a workflow body touches is addressable by alias with nothing to declare.
|
|
389
414
|
|
|
390
415
|
## SDK
|
|
391
416
|
|
package/dist/probe_page.js
CHANGED
|
@@ -21,9 +21,12 @@ var __loticsProbe = (() => {
|
|
|
21
21
|
// src/probe_page.ts
|
|
22
22
|
var probe_page_exports = {};
|
|
23
23
|
__export(probe_page_exports, {
|
|
24
|
-
|
|
24
|
+
PROBES: () => PROBES,
|
|
25
|
+
openRecord: () => openRecord,
|
|
26
|
+
openScreen: () => openScreen,
|
|
27
|
+
recordRows: () => recordRows,
|
|
25
28
|
run: () => run,
|
|
26
|
-
|
|
29
|
+
screens: () => screens,
|
|
27
30
|
textLeafCount: () => textLeafCount
|
|
28
31
|
});
|
|
29
32
|
|
|
@@ -99,23 +102,57 @@ var __loticsProbe = (() => {
|
|
|
99
102
|
const skipTag = /^(SCRIPT|STYLE|TITLE|META|LINK|NOSCRIPT|TEMPLATE)$/;
|
|
100
103
|
const notAValue = 'a, button, [role="tab"], [role="button"], input, th, [role="columnheader"], nav';
|
|
101
104
|
const pictureMin = 32;
|
|
102
|
-
const
|
|
103
|
-
|
|
105
|
+
const nameReach = 360;
|
|
106
|
+
const values = [];
|
|
107
|
+
const labels = [];
|
|
104
108
|
const walk = (node) => {
|
|
105
109
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
106
110
|
const text = (node.textContent || "").trim();
|
|
107
111
|
const parent = node.parentElement;
|
|
108
112
|
if (!text || !parent || skipTag.test(parent.tagName)) return;
|
|
109
113
|
if (typeof parent.checkVisibility === "function" && !parent.checkVisibility()) return;
|
|
110
|
-
|
|
114
|
+
const rect = parent.getBoundingClientRect();
|
|
115
|
+
if (rect.width === 0 && rect.height === 0) return;
|
|
116
|
+
const leaf = { text, left: Math.round(rect.left), right: Math.round(rect.right), top: Math.round(rect.top) };
|
|
117
|
+
if (!numeric.test(text) || dateLike.test(text)) {
|
|
118
|
+
labels.push(leaf);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
111
121
|
if (parent.closest(notAValue)) return;
|
|
112
|
-
|
|
113
|
-
if (samples.length < 6) samples.push(text);
|
|
122
|
+
values.push(leaf);
|
|
114
123
|
return;
|
|
115
124
|
}
|
|
116
125
|
node.childNodes.forEach(walk);
|
|
117
126
|
};
|
|
118
127
|
walk(document.body);
|
|
128
|
+
const clusters = [];
|
|
129
|
+
for (const leaf of [...values].sort((a, b) => a.left - b.left || a.top - b.top)) {
|
|
130
|
+
const cluster = clusters.find((c) => leaf.left < c.right && leaf.right > c.left);
|
|
131
|
+
if (cluster !== void 0) {
|
|
132
|
+
cluster.items.push(leaf);
|
|
133
|
+
cluster.left = Math.min(cluster.left, leaf.left);
|
|
134
|
+
cluster.right = Math.max(cluster.right, leaf.right);
|
|
135
|
+
} else {
|
|
136
|
+
clusters.push({ left: leaf.left, right: leaf.right, items: [leaf] });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const columns = [];
|
|
140
|
+
let bare = 0;
|
|
141
|
+
for (const cluster of clusters) {
|
|
142
|
+
const items = [...cluster.items].sort((a, b) => a.top - b.top);
|
|
143
|
+
const ordinal = items.length >= 3 && items.every((item, index) => item.text === String(index + 1));
|
|
144
|
+
if (ordinal) continue;
|
|
145
|
+
const top = items[0];
|
|
146
|
+
const above = labels.filter((label) => label.top < top.top && top.top - label.top <= nameReach && label.left < cluster.right && label.right > cluster.left).sort((a, b) => b.top - a.top)[0];
|
|
147
|
+
const beside = labels.filter((label) => Math.abs(label.top - top.top) <= 8 && label.right <= top.left).sort((a, b) => b.right - a.right)[0];
|
|
148
|
+
bare += items.length;
|
|
149
|
+
columns.push({
|
|
150
|
+
slot: (above ?? beside)?.text.slice(0, 40) ?? "",
|
|
151
|
+
size: items.length,
|
|
152
|
+
samples: items.slice(0, 4).map((item) => item.text)
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
columns.sort((a, b) => b.size - a.size);
|
|
119
156
|
const drawn = Array.from(document.querySelectorAll('[role="meter"], [role="progressbar"], canvas')).filter((el) => {
|
|
120
157
|
const r = el.getBoundingClientRect();
|
|
121
158
|
return r.width > 0 && r.height > 0;
|
|
@@ -126,7 +163,7 @@ var __loticsProbe = (() => {
|
|
|
126
163
|
return r.width >= pictureMin && r.height >= pictureMin;
|
|
127
164
|
});
|
|
128
165
|
const encoded = drawn.length + pictures.length;
|
|
129
|
-
return { total: bare + encoded, bare, encoded,
|
|
166
|
+
return { total: bare + encoded, bare, encoded, columns };
|
|
130
167
|
}
|
|
131
168
|
function internalIds() {
|
|
132
169
|
const skipTag = /^(SCRIPT|STYLE|TITLE|META|LINK|NOSCRIPT|TEMPLATE)$/;
|
|
@@ -149,11 +186,16 @@ var __loticsProbe = (() => {
|
|
|
149
186
|
return { total, ids: [...ids] };
|
|
150
187
|
}
|
|
151
188
|
function tabStrips() {
|
|
152
|
-
const
|
|
189
|
+
const all = Array.from(document.querySelectorAll('[role="tablist"]')).filter((el) => {
|
|
153
190
|
const r = el.getBoundingClientRect();
|
|
154
191
|
return r.width > 0 && r.height > 0;
|
|
155
|
-
})
|
|
156
|
-
|
|
192
|
+
});
|
|
193
|
+
const counted = all.filter((el) => el.getAttribute("data-order") !== "sequence");
|
|
194
|
+
return {
|
|
195
|
+
total: all.length,
|
|
196
|
+
counted: counted.length,
|
|
197
|
+
strips: counted.map((el) => Array.from(el.querySelectorAll('[role="tab"]')).map((tab) => (tab.textContent || "").trim()))
|
|
198
|
+
};
|
|
157
199
|
}
|
|
158
200
|
function truncatedLeaves() {
|
|
159
201
|
const skipTag = /^(SCRIPT|STYLE|TITLE|META|LINK|NOSCRIPT|TEMPLATE)$/;
|
|
@@ -301,6 +343,55 @@ var __loticsProbe = (() => {
|
|
|
301
343
|
}
|
|
302
344
|
|
|
303
345
|
// src/probe_page.ts
|
|
346
|
+
var PROBES = {
|
|
347
|
+
money_edges: {
|
|
348
|
+
section: "6",
|
|
349
|
+
fix: "One right edge per money column: give every figure in it the same alignment and the same unit."
|
|
350
|
+
},
|
|
351
|
+
reported_values: {
|
|
352
|
+
section: "9",
|
|
353
|
+
fix: "Encode the column the screen is ABOUT \u2014 a mark, a meter, a chart or a picture \u2014 and leave the rest as text."
|
|
354
|
+
},
|
|
355
|
+
internal_ids: {
|
|
356
|
+
section: "8",
|
|
357
|
+
fix: "A key is not a name: render the record's own label, and keep the id in the link."
|
|
358
|
+
},
|
|
359
|
+
tab_strips: {
|
|
360
|
+
section: "8a",
|
|
361
|
+
fix: "One navigation strip per screen. A second is a filter wearing navigation's clothes \u2014 draw it as one."
|
|
362
|
+
},
|
|
363
|
+
truncation: {
|
|
364
|
+
section: "8g",
|
|
365
|
+
fix: "Shed a trailing column or let the subject take two lines, so the distinguishing half of the name survives."
|
|
366
|
+
},
|
|
367
|
+
banned_glyph: {
|
|
368
|
+
section: "10",
|
|
369
|
+
fix: "No punctuation doing a word's job \u2014 separate the two facts with layout, or write the word."
|
|
370
|
+
},
|
|
371
|
+
compact_money_words: {
|
|
372
|
+
section: "10",
|
|
373
|
+
fix: "Abbreviate in the currency's own words: tr/t\u1EF7 beside \u20AB, K/M/B beside $ and \u20AC."
|
|
374
|
+
},
|
|
375
|
+
stacked_pairs: {
|
|
376
|
+
section: "1",
|
|
377
|
+
fix: "Demote once, not twice: either the size steps down or the subject gets the weight."
|
|
378
|
+
},
|
|
379
|
+
row_marks: {
|
|
380
|
+
section: "9",
|
|
381
|
+
fix: "One rung per row: a mark's size follows what the row is ABOUT, so the supporting mark takes the smaller one."
|
|
382
|
+
},
|
|
383
|
+
render: {
|
|
384
|
+
section: "8",
|
|
385
|
+
fix: "Open the screen and read it: nothing below this was measured, so a clean run over the rest means nothing."
|
|
386
|
+
},
|
|
387
|
+
settle: {
|
|
388
|
+
section: "9c",
|
|
389
|
+
fix: "A screen that never stops changing has a render that re-renders or a request that never lands \u2014 find which."
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
function signature(probe) {
|
|
393
|
+
return PROBES[probe];
|
|
394
|
+
}
|
|
304
395
|
var MONEY_EDGES_ALLOWED = 2;
|
|
305
396
|
var MONEY_COLUMN_MIN = 3;
|
|
306
397
|
var BARE_VALUES_FLOOR = 8;
|
|
@@ -311,6 +402,7 @@ var __loticsProbe = (() => {
|
|
|
311
402
|
if (ragged.length > 0) {
|
|
312
403
|
findings.push({
|
|
313
404
|
probe: "money_edges",
|
|
405
|
+
...signature("money_edges"),
|
|
314
406
|
total: money.total,
|
|
315
407
|
count: ragged.length,
|
|
316
408
|
detail: ragged.slice(0, 5).map((column) => `x=${column.x}: ${column.edges.length} right edges over ${column.size} figures \u2014 ${column.samples.join(" | ")}`)
|
|
@@ -320,21 +412,26 @@ var __loticsProbe = (() => {
|
|
|
320
412
|
if (values.bare >= BARE_VALUES_FLOOR && values.encoded === 0) {
|
|
321
413
|
findings.push({
|
|
322
414
|
probe: "reported_values",
|
|
415
|
+
...signature("reported_values"),
|
|
323
416
|
total: values.total,
|
|
324
417
|
count: values.bare,
|
|
325
|
-
detail: [
|
|
418
|
+
detail: [
|
|
419
|
+
`${values.bare} values as bare text, 0 as a mark, meter, chart or picture`,
|
|
420
|
+
...values.columns.slice(0, 5).map((column) => ` ${column.slot === "" ? "(unnamed)" : column.slot}: ${column.size} \u2014 ${column.samples.join(", ")}`)
|
|
421
|
+
]
|
|
326
422
|
});
|
|
327
423
|
}
|
|
328
424
|
const ids = internalIds();
|
|
329
425
|
if (ids.ids.length > 0) {
|
|
330
|
-
findings.push({ probe: "internal_ids", total: ids.total, count: ids.ids.length, detail: ids.ids.slice(0, 5) });
|
|
426
|
+
findings.push({ probe: "internal_ids", ...signature("internal_ids"), total: ids.total, count: ids.ids.length, detail: ids.ids.slice(0, 5) });
|
|
331
427
|
}
|
|
332
428
|
const strips = tabStrips();
|
|
333
|
-
if (strips.
|
|
429
|
+
if (strips.counted > 1) {
|
|
334
430
|
findings.push({
|
|
335
431
|
probe: "tab_strips",
|
|
432
|
+
...signature("tab_strips"),
|
|
336
433
|
total: strips.total,
|
|
337
|
-
count: strips.
|
|
434
|
+
count: strips.counted,
|
|
338
435
|
detail: strips.strips.map((strip) => strip.join(" / "))
|
|
339
436
|
});
|
|
340
437
|
}
|
|
@@ -343,6 +440,7 @@ var __loticsProbe = (() => {
|
|
|
343
440
|
if (cut.cut.length > 0) {
|
|
344
441
|
findings.push({
|
|
345
442
|
probe: "truncation",
|
|
443
|
+
...signature("truncation"),
|
|
346
444
|
total: cut.total,
|
|
347
445
|
count: cut.cut.length,
|
|
348
446
|
detail: cut.cut.slice(0, 5).map((leaf) => `"${leaf.text}" needs ${leaf.needs}px of ${leaf.axis} in ${leaf.has}px`)
|
|
@@ -351,12 +449,13 @@ var __loticsProbe = (() => {
|
|
|
351
449
|
}
|
|
352
450
|
const glyphs = bannedGlyphs();
|
|
353
451
|
if (glyphs.found.length > 0) {
|
|
354
|
-
findings.push({ probe: "banned_glyph", total: glyphs.total, count: glyphs.found.length, detail: glyphs.found.slice(0, 5) });
|
|
452
|
+
findings.push({ probe: "banned_glyph", ...signature("banned_glyph"), total: glyphs.total, count: glyphs.found.length, detail: glyphs.found.slice(0, 5) });
|
|
355
453
|
}
|
|
356
454
|
const compact = compactMoneyWords();
|
|
357
455
|
if (compact.foreign.length > 0) {
|
|
358
456
|
findings.push({
|
|
359
457
|
probe: "compact_money_words",
|
|
458
|
+
...signature("compact_money_words"),
|
|
360
459
|
total: compact.total,
|
|
361
460
|
count: compact.foreign.length,
|
|
362
461
|
detail: compact.foreign.slice(0, 5).map((text) => `"${text}" abbreviates in the other currency's words`)
|
|
@@ -366,6 +465,7 @@ var __loticsProbe = (() => {
|
|
|
366
465
|
if (pairs.overDemoted.length > 0) {
|
|
367
466
|
findings.push({
|
|
368
467
|
probe: "stacked_pairs",
|
|
468
|
+
...signature("stacked_pairs"),
|
|
369
469
|
total: pairs.total,
|
|
370
470
|
count: pairs.overDemoted.length,
|
|
371
471
|
detail: pairs.overDemoted.slice(0, 5).map((pair) => `"${pair.subject}" ${pair.sizes[0]}px/${pair.weights[0]} over "${pair.supporting}" ${pair.sizes[1]}px/${pair.weights[1]}`)
|
|
@@ -375,6 +475,7 @@ var __loticsProbe = (() => {
|
|
|
375
475
|
if (marks.mismatches.length > 0) {
|
|
376
476
|
findings.push({
|
|
377
477
|
probe: "row_marks",
|
|
478
|
+
...signature("row_marks"),
|
|
378
479
|
total: marks.total,
|
|
379
480
|
count: marks.mismatches.length,
|
|
380
481
|
detail: marks.mismatches.slice(0, 5).map((row) => `y=${row.y}: ${row.marks.join(", ")}`)
|
|
@@ -387,7 +488,7 @@ var __loticsProbe = (() => {
|
|
|
387
488
|
money: money.total,
|
|
388
489
|
bare: values.bare,
|
|
389
490
|
encoded: values.encoded,
|
|
390
|
-
strips: strips.
|
|
491
|
+
strips: strips.counted
|
|
391
492
|
}
|
|
392
493
|
};
|
|
393
494
|
}
|
|
@@ -405,16 +506,53 @@ var __loticsProbe = (() => {
|
|
|
405
506
|
walk(document.body);
|
|
406
507
|
return count;
|
|
407
508
|
}
|
|
408
|
-
function
|
|
509
|
+
function navItems() {
|
|
510
|
+
const nav = document.querySelector("nav");
|
|
511
|
+
if (nav === null) return [];
|
|
512
|
+
return Array.from(nav.querySelectorAll('a[href], [role="link"]')).filter(
|
|
513
|
+
(item) => (item.textContent || "").trim() !== ""
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
function tabItems() {
|
|
409
517
|
const strip = document.querySelector('[role="tablist"]');
|
|
410
518
|
if (strip === null) return [];
|
|
411
|
-
return Array.from(strip.querySelectorAll('[role="tab"]'))
|
|
519
|
+
return Array.from(strip.querySelectorAll('[role="tab"]'));
|
|
412
520
|
}
|
|
413
|
-
function
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
521
|
+
function screens() {
|
|
522
|
+
const nav = navItems();
|
|
523
|
+
if (nav.length > 0) return { source: "nav", labels: nav.map((item) => (item.textContent || "").trim()) };
|
|
524
|
+
const tabs = tabItems();
|
|
525
|
+
if (tabs.length > 0) return { source: "tabs", labels: tabs.map((item) => (item.textContent || "").trim()) };
|
|
526
|
+
return { source: "root", labels: [] };
|
|
527
|
+
}
|
|
528
|
+
function openScreen(source, index) {
|
|
529
|
+
const items = source === "nav" ? navItems() : source === "tabs" ? tabItems() : [];
|
|
530
|
+
const item = items[index];
|
|
531
|
+
if (item === void 0) return false;
|
|
532
|
+
item.click();
|
|
533
|
+
return true;
|
|
534
|
+
}
|
|
535
|
+
function recordLinks() {
|
|
536
|
+
const here = location.pathname + location.search;
|
|
537
|
+
const doors = Array.from(document.querySelectorAll('a[href], [data-opens="page"]'));
|
|
538
|
+
return doors.filter((door) => {
|
|
539
|
+
if (door.closest('nav, [role="banner"], [role="tablist"]') !== null) return false;
|
|
540
|
+
if (doors.some((other) => other !== door && other.contains(door))) return false;
|
|
541
|
+
const rect = door.getBoundingClientRect();
|
|
542
|
+
if (rect.width === 0 || rect.height === 0) return false;
|
|
543
|
+
const href = door.getAttribute("href");
|
|
544
|
+
if (href === null) return true;
|
|
545
|
+
if (href === "" || href.startsWith("http") || href.startsWith("#")) return false;
|
|
546
|
+
return href !== here;
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
function recordRows() {
|
|
550
|
+
return recordLinks().map((door) => (door.textContent || "").trim() || door.getAttribute("href") || "");
|
|
551
|
+
}
|
|
552
|
+
function openRecord(index) {
|
|
553
|
+
const door = recordLinks()[index];
|
|
554
|
+
if (door === void 0) return false;
|
|
555
|
+
door.click();
|
|
418
556
|
return true;
|
|
419
557
|
}
|
|
420
558
|
return __toCommonJS(probe_page_exports);
|