@plitzi/cli 0.38.10 → 0.38.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +178 -0
- package/README.md +9 -2
- package/dist/index.js +887 -677
- package/package.json +3 -3
- package/skills/plitzi-cli/reference/functions.md +7 -2
package/dist/index.js
CHANGED
|
@@ -14,8 +14,8 @@ import readline from "node:readline/promises";
|
|
|
14
14
|
import { EXPLAIN_KINDS, PAGE_SPEC_FIELDS, PAGE_TEXT_LIMIT, actionSpecFromEntry, actionToSource, authorSpace, blankTemplateFiles, catalogTemplateFiles, closest, comparePictures, compareTexts, darkScheme, dataIssues, elementTriggers, elementTypeNames, emptyTemplateFiles, explain, explainKindOf, explainList, explanationText, failedFlowText, importProbe, importedFiles, inspectDocument, inspectPage, isSuggestionCode, loadImages, locateClasses, locateElements, openPage, pageRegions, pageTexts, planFixes, readDevTools, refusalOf, unrollPage } from "@plitzi/sdk-authoring";
|
|
15
15
|
import { existsSync, readFileSync, readdirSync, realpathSync, statSync, watch } from "node:fs";
|
|
16
16
|
import { parseEnv, promisify } from "node:util";
|
|
17
|
-
import { lookup } from "node:dns/promises";
|
|
18
17
|
import esbuild, { build } from "esbuild";
|
|
18
|
+
import { lookup } from "node:dns/promises";
|
|
19
19
|
import { unzipSync, zipSync } from "fflate";
|
|
20
20
|
import { gzipSync } from "node:zlib";
|
|
21
21
|
import { emitKeypressEvents } from "node:readline";
|
|
@@ -24,6 +24,9 @@ var t$5 = `[data-plitzi-devtools] { display: none !important; }`;
|
|
|
24
24
|
//#region ../../packages/sdk-shared/dist/helpers/isRecord.mjs
|
|
25
25
|
var e$3 = (e) => typeof e == "object" && !!e && !Array.isArray(e);
|
|
26
26
|
//#endregion
|
|
27
|
+
//#region ../../packages/sdk-shared/dist/realtime/topics.mjs
|
|
28
|
+
var m$2 = "plitzi-observer";
|
|
29
|
+
//#endregion
|
|
27
30
|
//#region ../../packages/sdk-shared/dist/theme/themeCookie.mjs
|
|
28
31
|
var t$3 = "theme";
|
|
29
32
|
//#endregion
|
|
@@ -148,11 +151,15 @@ var openProjectPage = async (browser, origin, view) => {
|
|
|
148
151
|
colorScheme: view.scheme ?? "light",
|
|
149
152
|
reducedMotion: view.reducedMotion ? "reduce" : "no-preference"
|
|
150
153
|
});
|
|
151
|
-
|
|
154
|
+
await page.context().addCookies([...view.scheme ? [{
|
|
152
155
|
name: t$3,
|
|
153
156
|
value: view.scheme,
|
|
154
157
|
url: origin
|
|
155
|
-
}]
|
|
158
|
+
}] : [], ...view.presence ? [] : [{
|
|
159
|
+
name: m$2,
|
|
160
|
+
value: "1",
|
|
161
|
+
url: origin
|
|
162
|
+
}]]);
|
|
156
163
|
return page;
|
|
157
164
|
};
|
|
158
165
|
/**
|
|
@@ -1405,7 +1412,7 @@ var o$4 = () => ({
|
|
|
1405
1412
|
//#region src/scaffold/pluginPackage/names.ts
|
|
1406
1413
|
var PREFIX = "plitzi-plugin-";
|
|
1407
1414
|
/** npm's own rule for a package name, scope included. */
|
|
1408
|
-
var PACKAGE_NAME = /^(@[a-z0-9][a-z0-9-._~]*\/)?[a-z0-9][a-z0-9-._~]*$/;
|
|
1415
|
+
var PACKAGE_NAME$1 = /^(@[a-z0-9][a-z0-9-._~]*\/)?[a-z0-9][a-z0-9-._~]*$/;
|
|
1409
1416
|
/** What the name has to leave once the scope and prefix are off: words of letters and digits, starting with a letter. */
|
|
1410
1417
|
var BASE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
1411
1418
|
var baseOf = (packageName) => {
|
|
@@ -1414,7 +1421,7 @@ var baseOf = (packageName) => {
|
|
|
1414
1421
|
};
|
|
1415
1422
|
/** What is wrong with a name as a plugin's, in words that say how to fix it — or `undefined` when nothing is. */
|
|
1416
1423
|
var pluginNameProblem = (packageName) => {
|
|
1417
|
-
if (!PACKAGE_NAME.test(packageName)) return `"${packageName}" is not a package name npm accepts: lowercase letters, digits and dashes, optionally under a @scope/.`;
|
|
1424
|
+
if (!PACKAGE_NAME$1.test(packageName)) return `"${packageName}" is not a package name npm accepts: lowercase letters, digits and dashes, optionally under a @scope/.`;
|
|
1418
1425
|
if (!BASE.test(baseOf(packageName))) return `"${packageName}" has to name the plugin in words — lowercase letters and digits between single dashes, starting with a letter (seat-picker, chart2) — since the component and the type a space uses are made from it.`;
|
|
1419
1426
|
const { type } = pluginNames(packageName);
|
|
1420
1427
|
if (elementTypeNames.includes(type)) return `"${packageName}" would make the type "${type}", which is a built-in element: a space could not tell the two apart. Name it after what it does (seat-picker, sales-chart).`;
|
|
@@ -2512,7 +2519,7 @@ var YARN_IGNORES$1 = "\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases
|
|
|
2512
2519
|
* the CLI records about it, and is committed — a clone without it could not pull, push or upgrade.
|
|
2513
2520
|
*/
|
|
2514
2521
|
var gitignore$1 = ({ mode, packageManager }) => `node_modules\n${v$3}\n.env\ntmp\n${mode === "server" ? `${y$2}\n` : ""}${packageManager === "yarn" ? YARN_IGNORES$1 : ""}`;
|
|
2515
|
-
var startLine = ({ mode, packageManager, source }) => mode === "server" ? `\`${runCommand(packageManager, "start")}\` serves pages on http://127.0.0.1:8080 — or, when something else holds 8080, the next free port, which it prints and writes to \`${x$3}\` (set \`PORT\` to choose one). \`${runCommand(packageManager, "start:dev")}\` restarts on a save to the server's code; a save to a plugin swaps it in the open page${source === "local" ? ", and a save to the space reloads it" : ""}. In production, \`${runCommand(packageManager, "build")}\` once and run \`${runCommand(packageManager, "start:prod")}\`, which sets \`NODE_ENV=production\` itself: the compiled server, with no TypeScript in the process.` : `\`${runCommand(packageManager, "start")}\` runs Vite on http://127.0.0.1:5173, with hot module replacement.`;
|
|
2522
|
+
var startLine = ({ mode, packageManager, source }) => mode === "server" ? `\`${runCommand(packageManager, "start")}\` serves pages on http://127.0.0.1:8080 — or, when something else holds 8080, the next free port, which it prints and writes to \`${x$3}\` (set \`PORT\` to choose one; \`HOST=0.0.0.0\` opens it to your network — a tablet on the same Wi-Fi — and prints the address to open there). \`${runCommand(packageManager, "start:dev")}\` restarts on a save to the server's code; a save to a plugin swaps it in the open page${source === "local" ? ", and a save to the space reloads it" : ""}. In production, \`${runCommand(packageManager, "build")}\` once and run \`${runCommand(packageManager, "start:prod")}\`, which sets \`NODE_ENV=production\` itself: the compiled server, with no TypeScript in the process.` : `\`${runCommand(packageManager, "start")}\` runs Vite on http://127.0.0.1:5173, with hot module replacement.`;
|
|
2516
2523
|
var spaceSection = (answers) => {
|
|
2517
2524
|
if (answers.source === "cloud") return `## Where the space comes from
|
|
2518
2525
|
|
|
@@ -2724,6 +2731,12 @@ PLITZI_SIGNING_SECRET=
|
|
|
2724
2731
|
|
|
2725
2732
|
# Left out: 8080, or the next free port while developing.
|
|
2726
2733
|
# PORT=8080
|
|
2734
|
+
|
|
2735
|
+
# Left out: this machine only. 0.0.0.0 opens it to the network — a tablet on the same Wi-Fi, and anyone else on it.
|
|
2736
|
+
# HOST=0.0.0.0
|
|
2737
|
+
|
|
2738
|
+
# The secrets the space's actions and functions name — ctx.fetch's credential, a connector's: credential id → its keys.
|
|
2739
|
+
# PLITZI_CREDENTIALS={"google":{"clientId":"…","clientSecret":"…"}}
|
|
2727
2740
|
`;
|
|
2728
2741
|
/** A `.env` with the signing key `plitzi create` made for the project in its place. */
|
|
2729
2742
|
var withSigningSecret = (env, secret) => env.replace(/^PLITZI_SIGNING_SECRET=$/m, `PLITZI_SIGNING_SECRET=${secret}`);
|
|
@@ -6742,7 +6755,8 @@ var n$33 = t$60()({
|
|
|
6742
6755
|
data: "",
|
|
6743
6756
|
from: "",
|
|
6744
6757
|
user: "",
|
|
6745
|
-
at: ""
|
|
6758
|
+
at: "",
|
|
6759
|
+
echo: !1
|
|
6746
6760
|
}
|
|
6747
6761
|
},
|
|
6748
6762
|
onJoin: {
|
|
@@ -6784,6 +6798,11 @@ var n$33 = t$60()({
|
|
|
6784
6798
|
label: "Data (JSON or a template)",
|
|
6785
6799
|
defaultValue: "",
|
|
6786
6800
|
type: "text"
|
|
6801
|
+
},
|
|
6802
|
+
echo: {
|
|
6803
|
+
label: "Heard on this page too",
|
|
6804
|
+
defaultValue: !1,
|
|
6805
|
+
type: "boolean"
|
|
6787
6806
|
}
|
|
6788
6807
|
}
|
|
6789
6808
|
},
|
|
@@ -6809,7 +6828,7 @@ var n$33 = t$60()({
|
|
|
6809
6828
|
definition: {
|
|
6810
6829
|
label: "Channel",
|
|
6811
6830
|
type: "channel",
|
|
6812
|
-
description: "A realtime channel: every page on the same `topic` hears what
|
|
6831
|
+
description: "A realtime channel: every OTHER page on the same `topic` hears what one publishes, within milliseconds — the page that sent it too with `echo` (its `from` is then the channel's `me`). The topic must match a channel the space declares in its settings (`channels`), e.g. `board:{{ id }}` under `board:{id}`. A topic of a private channel (`grant: true`) opens only with `grant`, bound to the grant the action that let this visitor in returned (its `realtime.grant` step). ITS DESCENDANTS bind to its source `channel_<id>`: `connected`, `members` (with the state each announced), `messages` (the last `keep`) and `last`. It fires `onMessage`; `onJoin` when somebody who came after this page has announced who they are, and `onLeave` when somebody goes — each with `from`, `user` and the `state` they announced; and answers `publish({ type, data, echo })` and `setPresence({ data })`; `presence` is the state this page announces (a name, a colour). Closed in the builder and anywhere without a server.",
|
|
6813
6832
|
items: [],
|
|
6814
6833
|
bindings: {},
|
|
6815
6834
|
styleSelectors: { base: "" },
|
|
@@ -7980,10 +7999,15 @@ var AUTHORING_CODES = {
|
|
|
7980
7999
|
means: "a template in a page's `seoTitle`, `seoDescription` or `notFound` that reads what is not there when the server answers — anything but the page's `runtime: 'server'` providers and `navigation` — or cannot be read",
|
|
7981
8000
|
fix: "read the record from a provider with `runtime: 'server'` on the page or its layout — `'{{ apiContainer_post.title }} — Blog'` — or words of its own"
|
|
7982
8001
|
},
|
|
8002
|
+
"declared-callback-target": {
|
|
8003
|
+
kind: "refused",
|
|
8004
|
+
means: "a `declaredCallback` target with a key beside `on` and `params` — read nowhere, so the step runs without it",
|
|
8005
|
+
fix: "the value in `params`: `{ on: 'calendar', params: { date } }`"
|
|
8006
|
+
},
|
|
7983
8007
|
"folder-undeclared": {
|
|
7984
8008
|
kind: "refused",
|
|
7985
8009
|
means: "a page, a layout or a folder filed in a folder the space does not declare",
|
|
7986
|
-
fix: "declare the
|
|
8010
|
+
fix: "declare it on the space — `pageFolders: [{ id: 'docs', name: 'Docs' }]`, its slug starting its pages' addresses — or use the name it suggests"
|
|
7987
8011
|
},
|
|
7988
8012
|
"folder-cycle": {
|
|
7989
8013
|
kind: "refused",
|
|
@@ -8080,6 +8104,11 @@ var AUTHORING_CODES = {
|
|
|
8080
8104
|
means: "a `slots` key the element type does not have — its class would dress nothing",
|
|
8081
8105
|
fix: "one of the slots `plitzi explain <type>` lists; the element itself takes `class`"
|
|
8082
8106
|
},
|
|
8107
|
+
"slot-not-class": {
|
|
8108
|
+
kind: "refused",
|
|
8109
|
+
means: "a `slots` entry that is not a class — rules written in place, or nothing — which a slot cannot wear",
|
|
8110
|
+
fix: "the rules as a `styles()` declaration, handed to the slot beside its other classes"
|
|
8111
|
+
},
|
|
8083
8112
|
"class-conflict": {
|
|
8084
8113
|
kind: "refused",
|
|
8085
8114
|
means: "two different declarations for one class name",
|
|
@@ -8093,7 +8122,7 @@ var AUTHORING_CODES = {
|
|
|
8093
8122
|
"class-and-css": {
|
|
8094
8123
|
kind: "refused",
|
|
8095
8124
|
means: "an element wearing a shared class AND `css` or `states` of its own — it has one base selector",
|
|
8096
|
-
fix: "the rules on top of the class: `class: [card, { opacity: '0.5' }]`
|
|
8125
|
+
fix: "the rules on top of the class: `class: [card, { opacity: '0.5' }]` — or into the class"
|
|
8097
8126
|
},
|
|
8098
8127
|
"class-and-selector": {
|
|
8099
8128
|
kind: "refused",
|
|
@@ -8105,11 +8134,6 @@ var AUTHORING_CODES = {
|
|
|
8105
8134
|
means: "more than one set of rules in a class list",
|
|
8106
8135
|
fix: "one set, after the classes: `class: [card, { opacity: '0.5', 'margin-top': '8px' }]`"
|
|
8107
8136
|
},
|
|
8108
|
-
"modifier-without-id": {
|
|
8109
|
-
kind: "refused",
|
|
8110
|
-
means: "rules on top of a class on an element with no `id` — the id names the class they become",
|
|
8111
|
-
fix: "`id: 'hero-bg'`"
|
|
8112
|
-
},
|
|
8113
8137
|
"selector-invalid": {
|
|
8114
8138
|
kind: "refused",
|
|
8115
8139
|
means: "a `selector` that is not a CSS class name",
|
|
@@ -8390,6 +8414,11 @@ var AUTHORING_CODES = {
|
|
|
8390
8414
|
means: "a `runtime: 'server'` element inside a component: the page server resolves a page's and its layouts', never a component's",
|
|
8391
8415
|
fix: "put the provider on the page, around the instance, and hand the component its rows as a prop"
|
|
8392
8416
|
},
|
|
8417
|
+
"template-in-value": {
|
|
8418
|
+
kind: "refused",
|
|
8419
|
+
means: "a `{{ }}` inside an attribute that is an object or a list — a provider's `input`, a list's `items`, a plugin's settings: only an attribute that is text is evaluated",
|
|
8420
|
+
fix: "a binding on the attribute (`bindTemplate(name, source, template, { returns: 'value' })`); for a provider's `input`, nothing for a route or query param — the action is already handed them as `input.<name>`"
|
|
8421
|
+
},
|
|
8393
8422
|
"not-found-in-browser": {
|
|
8394
8423
|
kind: "refused",
|
|
8395
8424
|
means: "`notFound` on a provider asked from the browser — its answer arrives after the page was sent with its status",
|
|
@@ -9002,7 +9031,11 @@ var sourceRow = (listSource, items) => {
|
|
|
9002
9031
|
const shape = Reflect.get(items, SHAPE);
|
|
9003
9032
|
return {
|
|
9004
9033
|
item: pathTo(`${listSource}.item`, Array.isArray(shape) ? itemShape(shape) : UNKNOWN),
|
|
9005
|
-
index: pathTo(`${listSource}.index`, 0)
|
|
9034
|
+
index: pathTo(`${listSource}.index`, 0),
|
|
9035
|
+
inTemplate: {
|
|
9036
|
+
item: `${listSource}.item`,
|
|
9037
|
+
index: `${listSource}.index`
|
|
9038
|
+
}
|
|
9006
9039
|
};
|
|
9007
9040
|
};
|
|
9008
9041
|
var e$39 = [
|
|
@@ -10026,19 +10059,22 @@ var openModal = (target, metadata) => ({
|
|
|
10026
10059
|
params: metadata === void 0 ? {} : { metadata }
|
|
10027
10060
|
});
|
|
10028
10061
|
/**
|
|
10029
|
-
* Says something on a `channel`, by id: every page on its topic hears it — `onMessage`, and the channel's source.
|
|
10062
|
+
* Says something on a `channel`, by id: every OTHER page on its topic hears it — `onMessage`, and the channel's source.
|
|
10063
|
+
* The page that said it hears it too with `{ echo: true }` — a reaction, a chat line: what the sender shows the moment
|
|
10064
|
+
* it sends — once the server took it, its `from` the channel's `me`.
|
|
10030
10065
|
*
|
|
10031
10066
|
* `data` is what they receive: a template (`'{{ state.draft }}'`) or JSON text. `type` is yours to name — `chat`,
|
|
10032
10067
|
* `wave`, `move` — and a flow on `onMessage` tells them apart with `when({ field: '<step>.type', … })`.
|
|
10033
10068
|
*/
|
|
10034
|
-
var publishOn = (target, type, data = null) => ({
|
|
10069
|
+
var publishOn = (target, type, data = null, { echo = false } = {}) => ({
|
|
10035
10070
|
type: "callback",
|
|
10036
10071
|
action: "publish",
|
|
10037
10072
|
title: "Publish",
|
|
10038
10073
|
on: target,
|
|
10039
10074
|
params: {
|
|
10040
10075
|
type,
|
|
10041
|
-
data: typeof data === "string" ? data : JSON.stringify(data)
|
|
10076
|
+
data: typeof data === "string" ? data : JSON.stringify(data),
|
|
10077
|
+
...echo ? { echo } : {}
|
|
10042
10078
|
}
|
|
10043
10079
|
});
|
|
10044
10080
|
/** Announces this page on a `channel` with presence — a name, a colour: what the other members see of it. */
|
|
@@ -10145,6 +10181,12 @@ var declaredTrigger = (declaration, trigger) => {
|
|
|
10145
10181
|
*/
|
|
10146
10182
|
var declaredCallback = (declaration, callback, target) => {
|
|
10147
10183
|
const declared = declaration.callbacks?.[callback];
|
|
10184
|
+
const stray = Object.keys(target).filter((key) => key !== "on" && key !== "params");
|
|
10185
|
+
if (stray.length > 0) {
|
|
10186
|
+
const named = Object.keys(declared?.params ?? {});
|
|
10187
|
+
const moved = stray.map((key) => `${key}: ${JSON.stringify(Reflect.get(target, key))}`).join(", ");
|
|
10188
|
+
throw new AuthoringError("declared-callback-target", `declaredCallback(…, '${callback}') is given ${stray.map((key) => `"${key}"`).join(", ")} beside \`on\`, where nothing reads it${stray.every((key) => named.includes(key)) ? ` — ${stray.length === 1 ? "it is a param" : "they are params"} of "${callback}"` : ""}: a callback's values go in \`params\` — \`{ on: '${target.on}', params: { ${moved} } }\`.`);
|
|
10189
|
+
}
|
|
10148
10190
|
return {
|
|
10149
10191
|
type: "callback",
|
|
10150
10192
|
action: declared?.action ?? callback,
|
|
@@ -10874,525 +10916,73 @@ var e$9 = "/data/";
|
|
|
10874
10916
|
var e$7 = (e) => typeof e == "string" && /\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}/.test(e);
|
|
10875
10917
|
var i$5 = (e) => `value|round(0, '${e}')`;
|
|
10876
10918
|
i$5("floor"), i$5("ceil");
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
var
|
|
10880
|
-
new Set(
|
|
10881
|
-
|
|
10882
|
-
var
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10919
|
+
/** Every kebab-case CSS property Plitzi's style engine understands. Values written to a definition must use these
|
|
10920
|
+
* exact keys — camelCase or unknown keys are rejected. */
|
|
10921
|
+
var cssProperties = Array.from(new Set(Object.values(t$30))).sort();
|
|
10922
|
+
var cssPropertySet = new Set(cssProperties);
|
|
10923
|
+
var isCssProperty = (key) => cssPropertySet.has(key);
|
|
10924
|
+
var toKebab = (key) => key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
10925
|
+
/**
|
|
10926
|
+
* A property as an author may write it, in the spelling the document keeps: kebab-case already, or camelCase the way a
|
|
10927
|
+
* React style object writes it — `paddingTop` is `padding-top`, `WebkitLineClamp` is `-webkit-line-clamp`. A custom
|
|
10928
|
+
* property (`--brand`) is the author's own spelling and is kept.
|
|
10929
|
+
*/
|
|
10930
|
+
var cssPropertyName = (key) => {
|
|
10931
|
+
if (isCustomProperty(key) || !/[A-Z]/.test(key)) return key;
|
|
10932
|
+
return /^(Webkit|Moz|Ms|O)(?=[A-Z])/.exec(key) ? `-${toKebab(key)}` : toKebab(key);
|
|
10890
10933
|
};
|
|
10891
|
-
|
|
10892
|
-
|
|
10893
|
-
|
|
10894
|
-
|
|
10895
|
-
|
|
10896
|
-
"
|
|
10897
|
-
"
|
|
10934
|
+
/**
|
|
10935
|
+
* The properties a bare number is a whole value of — a weight, an opacity, a count, a ratio. Anywhere else a number is
|
|
10936
|
+
* a length, and a length without a unit is no value at all: `gap: 16` is `16px`.
|
|
10937
|
+
*/
|
|
10938
|
+
var UNITLESS = /* @__PURE__ */ new Set([
|
|
10939
|
+
"opacity",
|
|
10940
|
+
"z-index",
|
|
10941
|
+
"font-weight",
|
|
10942
|
+
"line-height",
|
|
10943
|
+
"flex",
|
|
10944
|
+
"flex-grow",
|
|
10945
|
+
"flex-shrink",
|
|
10946
|
+
"order",
|
|
10947
|
+
"column-count",
|
|
10948
|
+
"aspect-ratio",
|
|
10949
|
+
"orphans",
|
|
10950
|
+
"widows",
|
|
10951
|
+
"zoom",
|
|
10898
10952
|
"scale",
|
|
10899
|
-
"
|
|
10900
|
-
"
|
|
10901
|
-
"
|
|
10902
|
-
"
|
|
10903
|
-
"
|
|
10904
|
-
"
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
"
|
|
10908
|
-
"
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
var
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
"bounce",
|
|
10917
|
-
"wobble",
|
|
10918
|
-
"orbit",
|
|
10919
|
-
"heartbeat",
|
|
10920
|
-
"drift"
|
|
10921
|
-
];
|
|
10922
|
-
var o$6 = {
|
|
10923
|
-
fade: [{
|
|
10924
|
-
at: 0,
|
|
10925
|
-
opacity: 0
|
|
10926
|
-
}],
|
|
10927
|
-
"fade-up": [{
|
|
10928
|
-
at: 0,
|
|
10929
|
-
opacity: 0,
|
|
10930
|
-
translate: "0 24px"
|
|
10931
|
-
}],
|
|
10932
|
-
"fade-down": [{
|
|
10933
|
-
at: 0,
|
|
10934
|
-
opacity: 0,
|
|
10935
|
-
translate: "0 -24px"
|
|
10936
|
-
}],
|
|
10937
|
-
"slide-left": [{
|
|
10938
|
-
at: 0,
|
|
10939
|
-
opacity: 0,
|
|
10940
|
-
translate: "32px 0"
|
|
10941
|
-
}],
|
|
10942
|
-
"slide-right": [{
|
|
10943
|
-
at: 0,
|
|
10944
|
-
opacity: 0,
|
|
10945
|
-
translate: "-32px 0"
|
|
10946
|
-
}],
|
|
10947
|
-
"slide-up": [{
|
|
10948
|
-
at: 0,
|
|
10949
|
-
opacity: 0,
|
|
10950
|
-
translate: "0 72px"
|
|
10951
|
-
}],
|
|
10952
|
-
scale: [{
|
|
10953
|
-
at: 0,
|
|
10954
|
-
opacity: 0,
|
|
10955
|
-
scale: "0.94"
|
|
10956
|
-
}],
|
|
10957
|
-
"zoom-in": [{
|
|
10958
|
-
at: 0,
|
|
10959
|
-
opacity: 0,
|
|
10960
|
-
scale: "0.6"
|
|
10961
|
-
}],
|
|
10962
|
-
"zoom-out": [{
|
|
10963
|
-
at: 0,
|
|
10964
|
-
opacity: 0,
|
|
10965
|
-
scale: "1.25"
|
|
10966
|
-
}],
|
|
10967
|
-
pop: [
|
|
10968
|
-
{
|
|
10969
|
-
at: 0,
|
|
10970
|
-
opacity: 0,
|
|
10971
|
-
scale: "0.5"
|
|
10972
|
-
},
|
|
10973
|
-
{
|
|
10974
|
-
at: 55,
|
|
10975
|
-
opacity: 1,
|
|
10976
|
-
scale: "1.08"
|
|
10977
|
-
},
|
|
10978
|
-
{
|
|
10979
|
-
at: 78,
|
|
10980
|
-
scale: "0.97"
|
|
10981
|
-
}
|
|
10982
|
-
],
|
|
10983
|
-
"bounce-in": [
|
|
10984
|
-
{
|
|
10985
|
-
at: 0,
|
|
10986
|
-
opacity: 0,
|
|
10987
|
-
translate: "0 -64px"
|
|
10988
|
-
},
|
|
10989
|
-
{
|
|
10990
|
-
at: 55,
|
|
10991
|
-
opacity: 1,
|
|
10992
|
-
translate: "0 10px"
|
|
10993
|
-
},
|
|
10994
|
-
{
|
|
10995
|
-
at: 75,
|
|
10996
|
-
translate: "0 -5px"
|
|
10997
|
-
},
|
|
10998
|
-
{
|
|
10999
|
-
at: 90,
|
|
11000
|
-
translate: "0 2px"
|
|
11001
|
-
}
|
|
11002
|
-
],
|
|
11003
|
-
tilt: [{
|
|
11004
|
-
at: 0,
|
|
11005
|
-
opacity: 0,
|
|
11006
|
-
translate: "0 32px",
|
|
11007
|
-
rotate: "-6deg"
|
|
11008
|
-
}],
|
|
11009
|
-
"spin-in": [{
|
|
11010
|
-
at: 0,
|
|
11011
|
-
opacity: 0,
|
|
11012
|
-
scale: "0.4",
|
|
11013
|
-
rotate: "-180deg"
|
|
11014
|
-
}]
|
|
11015
|
-
};
|
|
11016
|
-
Object.fromEntries(t$6.map((e) => {
|
|
11017
|
-
let [{ at: t, ...n }] = o$6[e];
|
|
11018
|
-
return [e, n];
|
|
11019
|
-
}));
|
|
11020
|
-
var c$4 = (e, t) => {
|
|
11021
|
-
let n = t * 2 * Math.PI, r = Math.round(Math.sin(n) * e * 10) / 10, i = Math.round(-Math.cos(n) * e * 10) / 10;
|
|
11022
|
-
return `translate(${String(r)}px, ${String(i)}px)`;
|
|
10953
|
+
"tab-size",
|
|
10954
|
+
"animation-iteration-count",
|
|
10955
|
+
"grid-row-start",
|
|
10956
|
+
"grid-row-end",
|
|
10957
|
+
"grid-column-start",
|
|
10958
|
+
"grid-column-end",
|
|
10959
|
+
"fill-opacity",
|
|
10960
|
+
"stroke-opacity",
|
|
10961
|
+
"stroke-width",
|
|
10962
|
+
"-webkit-line-clamp"
|
|
10963
|
+
]);
|
|
10964
|
+
/** A number written as a value, as CSS reads it: itself where a bare number is a whole value, pixels otherwise. */
|
|
10965
|
+
var cssNumberValue = (property, value) => UNITLESS.has(property) || isCustomProperty(property) || value === 0 ? value : `${String(value)}px`;
|
|
10966
|
+
/** If a camelCase key maps to a known kebab-case property, return it — used to name the correct key in an error. */
|
|
10967
|
+
var suggestCssProperty = (key) => {
|
|
10968
|
+
const kebab = toKebab(key);
|
|
10969
|
+
return cssPropertySet.has(kebab) ? kebab : void 0;
|
|
11023
10970
|
};
|
|
11024
|
-
Array.from({ length: 9 }, (e, t) => ({
|
|
11025
|
-
at: t * 100 / 8,
|
|
11026
|
-
transform: c$4(6, t / 8)
|
|
11027
|
-
}));
|
|
11028
|
-
[
|
|
11029
|
-
"[data-motion-loop] { animation-play-state: running, running !important; }",
|
|
11030
|
-
"[data-motion-on=\"view\"][data-motion-enter], [data-motion-on=\"view\"][data-motion-stagger] > * { animation-play-state: running, running !important; }",
|
|
11031
|
-
"[data-motion-on=\"scroll\"][data-motion-enter], [data-motion-on=\"scroll\"][data-motion-stagger] > * { animation-timeline: auto, auto !important; }"
|
|
11032
|
-
].join("\n");
|
|
11033
|
-
Object.entries(AUTHORING_CODES).filter(([, entry]) => entry.kind === "suggested").map(([code]) => code);
|
|
11034
|
-
var URL_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
|
|
11035
|
-
/** A page target that is really a URL: the one reading of `mailto:`/`https:` a page-mode link can never mean. */
|
|
11036
|
-
var isUrlTarget = (target) => typeof target === "string" && !e$7(target) && URL_SCHEME.test(target);
|
|
11037
|
-
var isRoot = (element) => !element.definition.parentId;
|
|
11038
|
-
var stepsOf$1 = (element) => Object.values(element.definition.interactions ?? {});
|
|
11039
10971
|
/**
|
|
11040
|
-
* A
|
|
11041
|
-
*
|
|
10972
|
+
* A CSS custom property — `--brand`, `--space-4`.
|
|
10973
|
+
*
|
|
10974
|
+
* Not in the vocabulary and deliberately allowed anyway: a custom property is a declaration the browser resolves,
|
|
10975
|
+
* not one the style editor has to offer a control for, and a space that defines its palette in one place and reads
|
|
10976
|
+
* it back with `var(--brand)` is doing the right thing.
|
|
11042
10977
|
*/
|
|
11043
|
-
var
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
11049
|
-
|
|
11050
|
-
|
|
11051
|
-
Reflect.deleteProperty(record, key);
|
|
11052
|
-
report(`Moved ${inners.join(", ")} out of the ${what} "${key}", up to where ${inners.length === 1 ? "it is" : "they are"} read.`, {
|
|
11053
|
-
on,
|
|
11054
|
-
op: "unwrap",
|
|
11055
|
-
key
|
|
11056
|
-
});
|
|
11057
|
-
}
|
|
11058
|
-
continue;
|
|
11059
|
-
}
|
|
11060
|
-
const meant = closest$1(key, known);
|
|
11061
|
-
if (meant !== void 0 && record[meant] === void 0) {
|
|
11062
|
-
record[meant] = record[key];
|
|
11063
|
-
report(`Renamed the ${what} "${key}" to "${meant}".`, {
|
|
11064
|
-
on,
|
|
11065
|
-
op: "rename",
|
|
11066
|
-
key,
|
|
11067
|
-
to: meant
|
|
11068
|
-
});
|
|
11069
|
-
} else report(`Removed the ${what} "${key}", which nothing reads.`, {
|
|
11070
|
-
on,
|
|
11071
|
-
op: "remove",
|
|
11072
|
-
key
|
|
11073
|
-
});
|
|
11074
|
-
Reflect.deleteProperty(record, key);
|
|
11075
|
-
}
|
|
11076
|
-
};
|
|
11077
|
-
/** A flag written as the words `'true'`/`'false'`, stored as the boolean it is read as. */
|
|
11078
|
-
var asFlag = (value) => value === "true" ? true : value === "false" ? false : void 0;
|
|
11079
|
-
var stepSpec = (catalogs, step) => {
|
|
11080
|
-
const vocabulary = catalogs.vocabulary;
|
|
11081
|
-
const table = step.type === "globalCallback" ? vocabulary?.globalCallbacks : step.type === "utility" ? vocabulary?.utilities : step.type === "callback" ? vocabulary?.sharedCallbacks : void 0;
|
|
11082
|
-
return table && Object.hasOwn(table, step.action) ? table[step.action] : void 0;
|
|
11083
|
-
};
|
|
11084
|
-
new Set(Object.keys({
|
|
11085
|
-
"page-target-url": (element, _ctx, report) => {
|
|
11086
|
-
const { href, mode } = element.attributes;
|
|
11087
|
-
if (element.definition.type === "link" && (mode ?? "page") === "page" && isUrlTarget(href)) {
|
|
11088
|
-
element.attributes.mode = "external";
|
|
11089
|
-
report(`The link to "${href}" now opens it as an external URL.`, {
|
|
11090
|
-
on: "attribute",
|
|
11091
|
-
op: "set",
|
|
11092
|
-
key: "mode",
|
|
11093
|
-
value: "external"
|
|
11094
|
-
});
|
|
11095
|
-
}
|
|
11096
|
-
for (const step of stepsOf$1(element)) if (step.action === "navigate" && step.params.urlType === "page" && isUrlTarget(step.params.url)) {
|
|
11097
|
-
step.params.urlType = "external";
|
|
11098
|
-
report(`Step "${step.id}" now navigates to "${step.params.url}" as an external URL.`, {
|
|
11099
|
-
on: { step: step.id },
|
|
11100
|
-
op: "set",
|
|
11101
|
-
key: "urlType",
|
|
11102
|
-
value: "external"
|
|
11103
|
-
});
|
|
11104
|
-
}
|
|
11105
|
-
},
|
|
11106
|
-
"unknown-attribute": (element, ctx, report) => {
|
|
11107
|
-
const names = ctx.attributeNamesFor(element);
|
|
11108
|
-
if (!isRoot(element) && names) settleUnknownKeys(element.attributes, names, "attribute", "attribute", report, ctx.defaultsFor(element));
|
|
11109
|
-
},
|
|
11110
|
-
"attribute-kind": (element, ctx, report) => {
|
|
11111
|
-
const defaults = ctx.catalogs.defaultAttributes?.[element.definition.type] ?? {};
|
|
11112
|
-
for (const [name, value] of Object.entries(element.attributes)) {
|
|
11113
|
-
const flag = asFlag(value);
|
|
11114
|
-
if (typeof defaults[name] === "boolean" && flag !== void 0) {
|
|
11115
|
-
element.attributes[name] = flag;
|
|
11116
|
-
report(`\`${name}\` is now the boolean ${String(flag)}, not the text "${String(value)}".`, {
|
|
11117
|
-
on: "attribute",
|
|
11118
|
-
op: "set",
|
|
11119
|
-
key: name,
|
|
11120
|
-
value: flag
|
|
11121
|
-
});
|
|
11122
|
-
}
|
|
11123
|
-
}
|
|
11124
|
-
},
|
|
11125
|
-
"step-params": (element, ctx, report) => {
|
|
11126
|
-
for (const step of stepsOf$1(element)) {
|
|
11127
|
-
const spec = stepSpec(ctx.catalogs, step);
|
|
11128
|
-
if (!spec?.params) continue;
|
|
11129
|
-
const params = spec.params;
|
|
11130
|
-
if (spec.strictParams) settleUnknownKeys(step.params, Object.keys(params), `param of step "${step.id}"`, { step: step.id }, report);
|
|
11131
|
-
for (const [key, value] of Object.entries(step.params)) {
|
|
11132
|
-
const flag = asFlag(value);
|
|
11133
|
-
if (Object.hasOwn(params, key) && params[key].type === "boolean" && flag !== void 0) {
|
|
11134
|
-
step.params[key] = flag;
|
|
11135
|
-
report(`Step "${step.id}": \`${key}\` is now the boolean ${String(flag)}.`, {
|
|
11136
|
-
on: { step: step.id },
|
|
11137
|
-
op: "set",
|
|
11138
|
-
key,
|
|
11139
|
-
value: flag
|
|
11140
|
-
});
|
|
11141
|
-
}
|
|
11142
|
-
}
|
|
11143
|
-
}
|
|
11144
|
-
},
|
|
11145
|
-
"global-callback-module": (element, ctx, report) => {
|
|
11146
|
-
for (const step of stepsOf$1(element)) {
|
|
11147
|
-
const declared = step.type === "globalCallback" && ctx.catalogs.vocabulary ? ctx.catalogs.vocabulary.globalCallbacks[step.action] : void 0;
|
|
11148
|
-
if (declared && step.elementId !== declared.source) {
|
|
11149
|
-
step.elementId = declared.source;
|
|
11150
|
-
report(`Step "${step.id}" now runs "${step.action}" on "${declared.source}", the module that registers it.`, {
|
|
11151
|
-
on: { step: step.id },
|
|
11152
|
-
op: "set",
|
|
11153
|
-
key: "on",
|
|
11154
|
-
value: declared.source
|
|
11155
|
-
});
|
|
11156
|
-
}
|
|
11157
|
-
}
|
|
11158
|
-
},
|
|
11159
|
-
"utility-module": (element, ctx, report) => {
|
|
11160
|
-
for (const step of stepsOf$1(element)) {
|
|
11161
|
-
const known = ctx.catalogs.vocabulary ? Object.hasOwn(ctx.catalogs.vocabulary.utilities, step.action) : false;
|
|
11162
|
-
if (step.type === "utility" && known && step.elementId !== null) {
|
|
11163
|
-
step.elementId = null;
|
|
11164
|
-
report(`Step "${step.id}" runs the utility "${step.action}" on no element: a utility takes none.`, {
|
|
11165
|
-
on: { step: step.id },
|
|
11166
|
-
op: "remove",
|
|
11167
|
-
key: "on"
|
|
11168
|
-
});
|
|
11169
|
-
}
|
|
11170
|
-
}
|
|
11171
|
-
},
|
|
11172
|
-
"visibility-as-attribute": (element, _ctx, report) => {
|
|
11173
|
-
const bindings = element.definition.bindings;
|
|
11174
|
-
const moved = bindings?.attributes?.filter((binding) => binding.to === "visibility") ?? [];
|
|
11175
|
-
if (!bindings || moved.length === 0) return;
|
|
11176
|
-
bindings.attributes = bindings.attributes?.filter((binding) => binding.to !== "visibility");
|
|
11177
|
-
bindings.initialState = [...bindings.initialState ?? [], ...moved];
|
|
11178
|
-
report("The visibility binding now sets the visibility, rather than an attribute nothing reads.");
|
|
11179
|
-
},
|
|
11180
|
-
"binding-target-unknown": (element, ctx, report) => {
|
|
11181
|
-
const names = ctx.attributeNamesFor(element);
|
|
11182
|
-
const bindings = element.definition.bindings;
|
|
11183
|
-
if (!names || !bindings?.attributes) return;
|
|
11184
|
-
const reads = (binding) => binding.to === "visibility" || binding.to === "className" || names.includes(binding.to);
|
|
11185
|
-
for (const binding of bindings.attributes.filter((candidate) => !reads(candidate))) report(`Removed the binding onto "${binding.to}", which a "${element.definition.type}" never reads.`, {
|
|
11186
|
-
on: "binding",
|
|
11187
|
-
op: "remove",
|
|
11188
|
-
key: binding.to
|
|
11189
|
-
});
|
|
11190
|
-
bindings.attributes = bindings.attributes.filter(reads);
|
|
11191
|
-
},
|
|
11192
|
-
"unknown-transformer": (element, ctx, report) => {
|
|
11193
|
-
const catalog = ctx.catalogs.transformers;
|
|
11194
|
-
if (!catalog) return;
|
|
11195
|
-
for (const binding of Object.values(element.definition.bindings ?? {}).flat()) for (const transformer of binding.transformers ?? []) {
|
|
11196
|
-
const meant = Object.hasOwn(catalog, transformer.action) ? void 0 : closest$1(transformer.action, Object.keys(catalog));
|
|
11197
|
-
if (meant !== void 0) {
|
|
11198
|
-
report(`The binding of "${binding.to}" now runs "${meant}" (was "${transformer.action}").`, {
|
|
11199
|
-
on: "binding",
|
|
11200
|
-
op: "replace",
|
|
11201
|
-
key: transformer.action,
|
|
11202
|
-
to: meant
|
|
11203
|
-
});
|
|
11204
|
-
transformer.action = meant;
|
|
11205
|
-
}
|
|
11206
|
-
}
|
|
11207
|
-
},
|
|
11208
|
-
"list-items-ignored": (element, _ctx, report) => {
|
|
11209
|
-
const { attributes } = element;
|
|
11210
|
-
const bound = Object.values(element.definition.bindings ?? {}).flat().some((binding) => binding.to === "items");
|
|
11211
|
-
const written = Array.isArray(attributes.items) && attributes.items.length > 0;
|
|
11212
|
-
if (element.definition.type === "list" && attributes.source !== "controlled" && (bound || written)) {
|
|
11213
|
-
attributes.source = "controlled";
|
|
11214
|
-
report("The list now reads its items (`source: controlled`), one row per item.", {
|
|
11215
|
-
on: "attribute",
|
|
11216
|
-
op: "set",
|
|
11217
|
-
key: "source",
|
|
11218
|
-
value: "controlled"
|
|
11219
|
-
});
|
|
11220
|
-
}
|
|
11221
|
-
},
|
|
11222
|
-
"list-row-not-li": (element, ctx, report) => {
|
|
11223
|
-
const { parentId } = element.definition;
|
|
11224
|
-
const list = parentId ? ctx.element(parentId) : void 0;
|
|
11225
|
-
if (list?.definition.type === "list" && list.attributes.source === "controlled" && isPlainContainer(element)) {
|
|
11226
|
-
element.attributes.subType = "li";
|
|
11227
|
-
report("The row is now an `<li>` (`subType: li`), an item of the list it renders in.", {
|
|
11228
|
-
on: "attribute",
|
|
11229
|
-
op: "set",
|
|
11230
|
-
key: "subType",
|
|
11231
|
-
value: "li"
|
|
11232
|
-
});
|
|
11233
|
-
}
|
|
11234
|
-
},
|
|
11235
|
-
"overlay-starts-open": (element, _ctx, report) => {
|
|
11236
|
-
const { type, bindings } = element.definition;
|
|
11237
|
-
const visibilityBound = (bindings?.initialState ?? []).some((binding) => binding.to === "visibility");
|
|
11238
|
-
if ((type === "modalContainer" || type === "dialogContainer") && element.definition.initialState?.visibility !== false && !visibilityBound) {
|
|
11239
|
-
element.definition.initialState = {
|
|
11240
|
-
...element.definition.initialState,
|
|
11241
|
-
visibility: false
|
|
11242
|
-
};
|
|
11243
|
-
report(`The ${type} now starts closed, to be opened from a flow.`, {
|
|
11244
|
-
on: "field",
|
|
11245
|
-
op: "set",
|
|
11246
|
-
key: "visible",
|
|
11247
|
-
value: false
|
|
11248
|
-
});
|
|
11249
|
-
}
|
|
11250
|
-
},
|
|
11251
|
-
"state-key-has-runtime-prefix": (element, _ctx, report) => {
|
|
11252
|
-
for (const step of stepsOf$1(element)) {
|
|
11253
|
-
if (step.type !== "globalCallback" || step.elementId !== "state") continue;
|
|
11254
|
-
for (const param of STATE_PATH_PARAMS[step.action] ?? []) {
|
|
11255
|
-
const value = step.params[param];
|
|
11256
|
-
if (typeof value === "string" && /^(?:runtime\.)?state\./.test(value)) {
|
|
11257
|
-
const next = value.replace(/^(?:runtime\.)?state\./, "");
|
|
11258
|
-
step.params[param] = next;
|
|
11259
|
-
report(`Step "${step.id}": \`${param}\` is now "${next}" (was "${value}").`, {
|
|
11260
|
-
on: { step: step.id },
|
|
11261
|
-
op: "set",
|
|
11262
|
-
key: param,
|
|
11263
|
-
value: next
|
|
11264
|
-
});
|
|
11265
|
-
}
|
|
11266
|
-
}
|
|
11267
|
-
}
|
|
11268
|
-
}
|
|
11269
|
-
}));
|
|
11270
|
-
var e$4 = ".Toastify__toast-container.plitzi-sdk-toasts";
|
|
11271
|
-
var t$4 = [
|
|
11272
|
-
{
|
|
11273
|
-
selector: e$4,
|
|
11274
|
-
fields: {
|
|
11275
|
-
background: ["--toastify-color-light", "--toastify-color-dark"],
|
|
11276
|
-
text: ["--toastify-text-color-light", "--toastify-text-color-dark"],
|
|
11277
|
-
success: ["--toastify-color-success"],
|
|
11278
|
-
danger: ["--toastify-color-error"],
|
|
11279
|
-
warning: ["--toastify-color-warning"],
|
|
11280
|
-
info: ["--toastify-color-info"],
|
|
11281
|
-
radius: ["--toastify-toast-bd-radius"],
|
|
11282
|
-
font: ["--toastify-font-family"],
|
|
11283
|
-
shadow: ["--toastify-toast-shadow"],
|
|
11284
|
-
padding: ["--toastify-toast-padding"],
|
|
11285
|
-
minHeight: ["--toastify-toast-min-height"]
|
|
11286
|
-
}
|
|
11287
|
-
},
|
|
11288
|
-
{
|
|
11289
|
-
selector: `:where(${e$4} .Toastify__toast)`,
|
|
11290
|
-
fields: {
|
|
11291
|
-
fontSize: ["font-size"],
|
|
11292
|
-
fontWeight: ["font-weight"],
|
|
11293
|
-
lineHeight: ["line-height"],
|
|
11294
|
-
border: ["border"]
|
|
11295
|
-
}
|
|
11296
|
-
},
|
|
11297
|
-
{
|
|
11298
|
-
selector: `${e$4} .Toastify__toast-icon`,
|
|
11299
|
-
fields: {
|
|
11300
|
-
iconSize: ["width"],
|
|
11301
|
-
iconGap: ["margin-inline-end"]
|
|
11302
|
-
}
|
|
11303
|
-
},
|
|
11304
|
-
{
|
|
11305
|
-
selector: `${e$4} .Toastify__close-button`,
|
|
11306
|
-
fields: { closeColor: ["color"] }
|
|
11307
|
-
},
|
|
11308
|
-
{
|
|
11309
|
-
selector: `${e$4} .Toastify__close-button:not(:hover, :focus)`,
|
|
11310
|
-
fields: { closeOpacity: ["opacity"] }
|
|
11311
|
-
},
|
|
11312
|
-
{
|
|
11313
|
-
selector: `${e$4} .Toastify__progress-bar--wrp`,
|
|
11314
|
-
fields: { progressHeight: ["height"] }
|
|
11315
|
-
}
|
|
11316
|
-
];
|
|
11317
|
-
var n$4 = t$4.flatMap((e) => Object.keys(e.fields));
|
|
11318
|
-
var r$2$1 = (e) => n$4.includes(e);
|
|
11319
|
-
n$4.filter(r$2$1);
|
|
11320
|
-
var c$2$1 = (e) => e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11321
|
-
t$4.map((e) => {
|
|
11322
|
-
let t = new Map(Object.entries(e.fields).flatMap(([e, t]) => r$2$1(e) ? t.map((t) => [t, e]) : []));
|
|
11323
|
-
return {
|
|
11324
|
-
pattern: RegExp(`(?:^|\\n)${c$2$1(e.selector)}\\s*\\{([^}]*)\\}`, "g"),
|
|
11325
|
-
fieldOf: (e) => t.get(e)
|
|
11326
|
-
};
|
|
11327
|
-
});
|
|
11328
|
-
Object.fromEntries(e$30.map((e) => [e, t$26(e)]));
|
|
11329
|
-
/** Every kebab-case CSS property Plitzi's style engine understands. Values written to a definition must use these
|
|
11330
|
-
* exact keys — camelCase or unknown keys are rejected. */
|
|
11331
|
-
var cssProperties = Array.from(new Set(Object.values(t$30))).sort();
|
|
11332
|
-
var cssPropertySet = new Set(cssProperties);
|
|
11333
|
-
var isCssProperty = (key) => cssPropertySet.has(key);
|
|
11334
|
-
var toKebab = (key) => key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
11335
|
-
/**
|
|
11336
|
-
* A property as an author may write it, in the spelling the document keeps: kebab-case already, or camelCase the way a
|
|
11337
|
-
* React style object writes it — `paddingTop` is `padding-top`, `WebkitLineClamp` is `-webkit-line-clamp`. A custom
|
|
11338
|
-
* property (`--brand`) is the author's own spelling and is kept.
|
|
11339
|
-
*/
|
|
11340
|
-
var cssPropertyName = (key) => {
|
|
11341
|
-
if (isCustomProperty(key) || !/[A-Z]/.test(key)) return key;
|
|
11342
|
-
return /^(Webkit|Moz|Ms|O)(?=[A-Z])/.exec(key) ? `-${toKebab(key)}` : toKebab(key);
|
|
11343
|
-
};
|
|
11344
|
-
/**
|
|
11345
|
-
* The properties a bare number is a whole value of — a weight, an opacity, a count, a ratio. Anywhere else a number is
|
|
11346
|
-
* a length, and a length without a unit is no value at all: `gap: 16` is `16px`.
|
|
11347
|
-
*/
|
|
11348
|
-
var UNITLESS = /* @__PURE__ */ new Set([
|
|
11349
|
-
"opacity",
|
|
11350
|
-
"z-index",
|
|
11351
|
-
"font-weight",
|
|
11352
|
-
"line-height",
|
|
11353
|
-
"flex",
|
|
11354
|
-
"flex-grow",
|
|
11355
|
-
"flex-shrink",
|
|
11356
|
-
"order",
|
|
11357
|
-
"column-count",
|
|
11358
|
-
"aspect-ratio",
|
|
11359
|
-
"orphans",
|
|
11360
|
-
"widows",
|
|
11361
|
-
"zoom",
|
|
11362
|
-
"scale",
|
|
11363
|
-
"tab-size",
|
|
11364
|
-
"animation-iteration-count",
|
|
11365
|
-
"grid-row-start",
|
|
11366
|
-
"grid-row-end",
|
|
11367
|
-
"grid-column-start",
|
|
11368
|
-
"grid-column-end",
|
|
11369
|
-
"fill-opacity",
|
|
11370
|
-
"stroke-opacity",
|
|
11371
|
-
"stroke-width",
|
|
11372
|
-
"-webkit-line-clamp"
|
|
11373
|
-
]);
|
|
11374
|
-
/** A number written as a value, as CSS reads it: itself where a bare number is a whole value, pixels otherwise. */
|
|
11375
|
-
var cssNumberValue = (property, value) => UNITLESS.has(property) || isCustomProperty(property) || value === 0 ? value : `${String(value)}px`;
|
|
11376
|
-
/** If a camelCase key maps to a known kebab-case property, return it — used to name the correct key in an error. */
|
|
11377
|
-
var suggestCssProperty = (key) => {
|
|
11378
|
-
const kebab = toKebab(key);
|
|
11379
|
-
return cssPropertySet.has(kebab) ? kebab : void 0;
|
|
11380
|
-
};
|
|
11381
|
-
/**
|
|
11382
|
-
* A CSS custom property — `--brand`, `--space-4`.
|
|
11383
|
-
*
|
|
11384
|
-
* Not in the vocabulary and deliberately allowed anyway: a custom property is a declaration the browser resolves,
|
|
11385
|
-
* not one the style editor has to offer a control for, and a space that defines its palette in one place and reads
|
|
11386
|
-
* it back with `var(--brand)` is doing the right thing.
|
|
11387
|
-
*/
|
|
11388
|
-
var isCustomProperty = (key) => key.startsWith("--");
|
|
11389
|
-
var walkTopLevel = (value, onChar) => {
|
|
11390
|
-
let depth = 0;
|
|
11391
|
-
let quote = "";
|
|
11392
|
-
for (const ch of value) {
|
|
11393
|
-
if (quote) {
|
|
11394
|
-
onChar(ch, false);
|
|
11395
|
-
if (ch === quote) quote = "";
|
|
10978
|
+
var isCustomProperty = (key) => key.startsWith("--");
|
|
10979
|
+
var walkTopLevel = (value, onChar) => {
|
|
10980
|
+
let depth = 0;
|
|
10981
|
+
let quote = "";
|
|
10982
|
+
for (const ch of value) {
|
|
10983
|
+
if (quote) {
|
|
10984
|
+
onChar(ch, false);
|
|
10985
|
+
if (ch === quote) quote = "";
|
|
11396
10986
|
continue;
|
|
11397
10987
|
}
|
|
11398
10988
|
if (/["']/.test(ch)) {
|
|
@@ -13704,114 +13294,566 @@ var byRange = (bucket) => {
|
|
|
13704
13294
|
}
|
|
13705
13295
|
return ranges;
|
|
13706
13296
|
};
|
|
13707
|
-
/**
|
|
13708
|
-
* A state's or an ancestor's declarations in one range, with the parts of the element's own composed properties it
|
|
13709
|
-
* builds on: `translate-x-2 hover:scale-105` is a hover transform that still translates.
|
|
13710
|
-
*/
|
|
13711
|
-
var onTopOf = (own, layer) => {
|
|
13712
|
-
const groups = new Set(Object.keys(layer).filter((key) => key.startsWith("@")).map(groupOf));
|
|
13713
|
-
const inherited = Object.entries(own).filter(([key]) => key.startsWith("@") && groups.has(groupOf(key)));
|
|
13714
|
-
return {
|
|
13715
|
-
...Object.fromEntries(inherited),
|
|
13716
|
-
...layer
|
|
13717
|
-
};
|
|
13297
|
+
/**
|
|
13298
|
+
* A state's or an ancestor's declarations in one range, with the parts of the element's own composed properties it
|
|
13299
|
+
* builds on: `translate-x-2 hover:scale-105` is a hover transform that still translates.
|
|
13300
|
+
*/
|
|
13301
|
+
var onTopOf = (own, layer) => {
|
|
13302
|
+
const groups = new Set(Object.keys(layer).filter((key) => key.startsWith("@")).map(groupOf));
|
|
13303
|
+
const inherited = Object.entries(own).filter(([key]) => key.startsWith("@") && groups.has(groupOf(key)));
|
|
13304
|
+
return {
|
|
13305
|
+
...Object.fromEntries(inherited),
|
|
13306
|
+
...layer
|
|
13307
|
+
};
|
|
13308
|
+
};
|
|
13309
|
+
/**
|
|
13310
|
+
* Desktop-first, as Plitzi writes it: the desktop rules apply everywhere, and tablet and mobile say only where they
|
|
13311
|
+
* differ — a property the desktop sets and a narrower range does not is `revert`, which is what "no rule here" is.
|
|
13312
|
+
*/
|
|
13313
|
+
var responsive = (ranges) => {
|
|
13314
|
+
const { desktop } = ranges;
|
|
13315
|
+
const differences = (range) => {
|
|
13316
|
+
const changed = Object.fromEntries(Object.entries(range).filter(([property, value]) => desktop[property] !== value));
|
|
13317
|
+
for (const property of Object.keys(desktop)) if (!Object.hasOwn(range, property)) changed[property] = "revert";
|
|
13318
|
+
return changed;
|
|
13319
|
+
};
|
|
13320
|
+
const tablet = differences(ranges.tablet);
|
|
13321
|
+
const mobile = differences(ranges.mobile);
|
|
13322
|
+
if (Object.keys(tablet).length === 0 && Object.keys(mobile).length === 0) return desktop;
|
|
13323
|
+
return {
|
|
13324
|
+
...Object.keys(desktop).length === 0 ? {} : { desktop },
|
|
13325
|
+
...Object.keys(tablet).length === 0 ? {} : { tablet },
|
|
13326
|
+
...Object.keys(mobile).length === 0 ? {} : { mobile }
|
|
13327
|
+
};
|
|
13328
|
+
};
|
|
13329
|
+
var rangesOf = (bucket, own) => {
|
|
13330
|
+
const layer = byRange(bucket);
|
|
13331
|
+
return {
|
|
13332
|
+
mobile: composed(own ? onTopOf(own.mobile, layer.mobile) : layer.mobile),
|
|
13333
|
+
tablet: composed(own ? onTopOf(own.tablet, layer.tablet) : layer.tablet),
|
|
13334
|
+
desktop: composed(own ? onTopOf(own.desktop, layer.desktop) : layer.desktop)
|
|
13335
|
+
};
|
|
13336
|
+
};
|
|
13337
|
+
/**
|
|
13338
|
+
* A `tw()` with colours of its own: `createTw({ colors: tokens(variables) })` makes `bg-surface` the space's token.
|
|
13339
|
+
*
|
|
13340
|
+
* `tw('flex items-center gap-2 px-5 py-2 rounded-full bg-slate-950/90 hover:scale-105 md:text-sm')` is the rules those
|
|
13341
|
+
* classes mean, written out when the space is — nothing of Tailwind runs in the page. Tailwind's breakpoints become
|
|
13342
|
+
* Plitzi's (`md:` tablet and desktop, `lg:` desktop, `max-md:` mobile, `max-lg:` tablet and mobile), its states the
|
|
13343
|
+
* class's states, `group-hover/<class>:` how it looks inside an ancestor wearing that class. A class Tailwind does not
|
|
13344
|
+
* have, or one with no exact equivalent here (`sm:`, `dark:`, `space-x-4`), is refused with what to write instead.
|
|
13345
|
+
*/
|
|
13346
|
+
var createTw = ({ colors = {} } = {}) => (classes) => {
|
|
13347
|
+
const buckets = /* @__PURE__ */ new Map([["|", {
|
|
13348
|
+
target: {},
|
|
13349
|
+
bucket: {}
|
|
13350
|
+
}]]);
|
|
13351
|
+
for (const written of classes.split(/\s+/).filter(Boolean)) {
|
|
13352
|
+
const { breakpoint, target, utility } = parseClass(written);
|
|
13353
|
+
const resolved = resolveUtility(utility, colors);
|
|
13354
|
+
if (resolved === void 0) return refuse$1("tw-unknown-class", `"${written}" is not a Tailwind class tw() knows${didYouMean(utility, KNOWN_NAMES)} A colour of the space is \`createTw({ colors })\`; any CSS at all is \`[property:value]\`.`);
|
|
13355
|
+
if (resolved instanceof NoEquivalent) return refuse$1("tw-no-equivalent", `"${written}": ${resolved.reason}`);
|
|
13356
|
+
const key = targetKey(target);
|
|
13357
|
+
const entry = buckets.get(key) ?? {
|
|
13358
|
+
target,
|
|
13359
|
+
bucket: {}
|
|
13360
|
+
};
|
|
13361
|
+
buckets.set(key, entry);
|
|
13362
|
+
const declared = entry.bucket[breakpoint] ?? /* @__PURE__ */ new Map();
|
|
13363
|
+
entry.bucket[breakpoint] = declared;
|
|
13364
|
+
const weight = Object.keys(resolved).length;
|
|
13365
|
+
for (const [property, value] of Object.entries(resolved)) {
|
|
13366
|
+
const earlier = declared.get(property);
|
|
13367
|
+
if (earlier && earlier.weight === weight && earlier.value !== value) return refuse$1("tw-class-conflict", `"${earlier.by}" and "${written}" both set \`${property}\`, and neither is the narrower one — Tailwind would pick by its own order, not yours. Keep one.`);
|
|
13368
|
+
if (!earlier || weight <= earlier.weight) declared.set(property, {
|
|
13369
|
+
value,
|
|
13370
|
+
weight,
|
|
13371
|
+
by: written
|
|
13372
|
+
});
|
|
13373
|
+
}
|
|
13374
|
+
}
|
|
13375
|
+
const own = buckets.get("|")?.bucket ?? {};
|
|
13376
|
+
const ownRanges = byRange(own);
|
|
13377
|
+
const rules = { css: responsive(rangesOf(own)) };
|
|
13378
|
+
for (const [key, { target, bucket }] of buckets) {
|
|
13379
|
+
if (key === "|") continue;
|
|
13380
|
+
const css = responsive(rangesOf(bucket, ownRanges));
|
|
13381
|
+
if (target.state) rules.states = {
|
|
13382
|
+
...rules.states,
|
|
13383
|
+
[target.state]: css
|
|
13384
|
+
};
|
|
13385
|
+
else if (target.ancestor) {
|
|
13386
|
+
const ancestors = { ...rules.ancestors };
|
|
13387
|
+
const { name, state } = target.ancestor;
|
|
13388
|
+
const ancestor = ancestors[name] ?? {};
|
|
13389
|
+
ancestors[name] = state ? {
|
|
13390
|
+
...ancestor,
|
|
13391
|
+
states: {
|
|
13392
|
+
...ancestor.states,
|
|
13393
|
+
[state]: css
|
|
13394
|
+
}
|
|
13395
|
+
} : {
|
|
13396
|
+
...ancestor,
|
|
13397
|
+
css
|
|
13398
|
+
};
|
|
13399
|
+
rules.ancestors = ancestors;
|
|
13400
|
+
}
|
|
13401
|
+
}
|
|
13402
|
+
return rules;
|
|
13403
|
+
};
|
|
13404
|
+
createTw();
|
|
13405
|
+
new Set(Object.entries(g$4.content.defaultStyle.subTypes).filter(([, variant]) => "field" in variant.style).map(([subType]) => subType));
|
|
13406
|
+
/** A container with no tag of its own named: the row `list-row-not-li` makes an `<li>` without asking. */
|
|
13407
|
+
var isPlainContainer = (element) => element.definition.type === "container" && (element.attributes.subType === void 0 || element.attributes.subType === "div");
|
|
13408
|
+
new Set(STEP_TYPES);
|
|
13409
|
+
/** A step's params that name a path under `runtime.state`, by action. */
|
|
13410
|
+
var STATE_PATH_PARAMS = {
|
|
13411
|
+
setState: ["key"],
|
|
13412
|
+
toggleState: ["key"],
|
|
13413
|
+
appendState: ["key"],
|
|
13414
|
+
removeState: ["key"],
|
|
13415
|
+
toggleInState: ["key"],
|
|
13416
|
+
clearState: ["key"],
|
|
13417
|
+
moveState: ["from", "to"]
|
|
13418
|
+
};
|
|
13419
|
+
var t$6 = [
|
|
13420
|
+
"fade",
|
|
13421
|
+
"fade-up",
|
|
13422
|
+
"fade-down",
|
|
13423
|
+
"slide-left",
|
|
13424
|
+
"slide-right",
|
|
13425
|
+
"slide-up",
|
|
13426
|
+
"scale",
|
|
13427
|
+
"zoom-in",
|
|
13428
|
+
"zoom-out",
|
|
13429
|
+
"pop",
|
|
13430
|
+
"bounce-in",
|
|
13431
|
+
"tilt",
|
|
13432
|
+
"spin-in"
|
|
13433
|
+
];
|
|
13434
|
+
var n$6 = [
|
|
13435
|
+
"load",
|
|
13436
|
+
"view",
|
|
13437
|
+
"scroll"
|
|
13438
|
+
];
|
|
13439
|
+
var r$4 = [
|
|
13440
|
+
"float",
|
|
13441
|
+
"pulse",
|
|
13442
|
+
"spin",
|
|
13443
|
+
"sway",
|
|
13444
|
+
"bounce",
|
|
13445
|
+
"wobble",
|
|
13446
|
+
"orbit",
|
|
13447
|
+
"heartbeat",
|
|
13448
|
+
"drift"
|
|
13449
|
+
];
|
|
13450
|
+
var o$6 = {
|
|
13451
|
+
fade: [{
|
|
13452
|
+
at: 0,
|
|
13453
|
+
opacity: 0
|
|
13454
|
+
}],
|
|
13455
|
+
"fade-up": [{
|
|
13456
|
+
at: 0,
|
|
13457
|
+
opacity: 0,
|
|
13458
|
+
translate: "0 24px"
|
|
13459
|
+
}],
|
|
13460
|
+
"fade-down": [{
|
|
13461
|
+
at: 0,
|
|
13462
|
+
opacity: 0,
|
|
13463
|
+
translate: "0 -24px"
|
|
13464
|
+
}],
|
|
13465
|
+
"slide-left": [{
|
|
13466
|
+
at: 0,
|
|
13467
|
+
opacity: 0,
|
|
13468
|
+
translate: "32px 0"
|
|
13469
|
+
}],
|
|
13470
|
+
"slide-right": [{
|
|
13471
|
+
at: 0,
|
|
13472
|
+
opacity: 0,
|
|
13473
|
+
translate: "-32px 0"
|
|
13474
|
+
}],
|
|
13475
|
+
"slide-up": [{
|
|
13476
|
+
at: 0,
|
|
13477
|
+
opacity: 0,
|
|
13478
|
+
translate: "0 72px"
|
|
13479
|
+
}],
|
|
13480
|
+
scale: [{
|
|
13481
|
+
at: 0,
|
|
13482
|
+
opacity: 0,
|
|
13483
|
+
scale: "0.94"
|
|
13484
|
+
}],
|
|
13485
|
+
"zoom-in": [{
|
|
13486
|
+
at: 0,
|
|
13487
|
+
opacity: 0,
|
|
13488
|
+
scale: "0.6"
|
|
13489
|
+
}],
|
|
13490
|
+
"zoom-out": [{
|
|
13491
|
+
at: 0,
|
|
13492
|
+
opacity: 0,
|
|
13493
|
+
scale: "1.25"
|
|
13494
|
+
}],
|
|
13495
|
+
pop: [
|
|
13496
|
+
{
|
|
13497
|
+
at: 0,
|
|
13498
|
+
opacity: 0,
|
|
13499
|
+
scale: "0.5"
|
|
13500
|
+
},
|
|
13501
|
+
{
|
|
13502
|
+
at: 55,
|
|
13503
|
+
opacity: 1,
|
|
13504
|
+
scale: "1.08"
|
|
13505
|
+
},
|
|
13506
|
+
{
|
|
13507
|
+
at: 78,
|
|
13508
|
+
scale: "0.97"
|
|
13509
|
+
}
|
|
13510
|
+
],
|
|
13511
|
+
"bounce-in": [
|
|
13512
|
+
{
|
|
13513
|
+
at: 0,
|
|
13514
|
+
opacity: 0,
|
|
13515
|
+
translate: "0 -64px"
|
|
13516
|
+
},
|
|
13517
|
+
{
|
|
13518
|
+
at: 55,
|
|
13519
|
+
opacity: 1,
|
|
13520
|
+
translate: "0 10px"
|
|
13521
|
+
},
|
|
13522
|
+
{
|
|
13523
|
+
at: 75,
|
|
13524
|
+
translate: "0 -5px"
|
|
13525
|
+
},
|
|
13526
|
+
{
|
|
13527
|
+
at: 90,
|
|
13528
|
+
translate: "0 2px"
|
|
13529
|
+
}
|
|
13530
|
+
],
|
|
13531
|
+
tilt: [{
|
|
13532
|
+
at: 0,
|
|
13533
|
+
opacity: 0,
|
|
13534
|
+
translate: "0 32px",
|
|
13535
|
+
rotate: "-6deg"
|
|
13536
|
+
}],
|
|
13537
|
+
"spin-in": [{
|
|
13538
|
+
at: 0,
|
|
13539
|
+
opacity: 0,
|
|
13540
|
+
scale: "0.4",
|
|
13541
|
+
rotate: "-180deg"
|
|
13542
|
+
}]
|
|
13543
|
+
};
|
|
13544
|
+
Object.fromEntries(t$6.map((e) => {
|
|
13545
|
+
let [{ at: t, ...n }] = o$6[e];
|
|
13546
|
+
return [e, n];
|
|
13547
|
+
}));
|
|
13548
|
+
var c$4 = (e, t) => {
|
|
13549
|
+
let n = t * 2 * Math.PI, r = Math.round(Math.sin(n) * e * 10) / 10, i = Math.round(-Math.cos(n) * e * 10) / 10;
|
|
13550
|
+
return `translate(${String(r)}px, ${String(i)}px)`;
|
|
13718
13551
|
};
|
|
13552
|
+
Array.from({ length: 9 }, (e, t) => ({
|
|
13553
|
+
at: t * 100 / 8,
|
|
13554
|
+
transform: c$4(6, t / 8)
|
|
13555
|
+
}));
|
|
13556
|
+
[
|
|
13557
|
+
"[data-motion-loop] { animation-play-state: running, running !important; }",
|
|
13558
|
+
"[data-motion-on=\"view\"][data-motion-enter], [data-motion-on=\"view\"][data-motion-stagger] > * { animation-play-state: running, running !important; }",
|
|
13559
|
+
"[data-motion-on=\"scroll\"][data-motion-enter], [data-motion-on=\"scroll\"][data-motion-stagger] > * { animation-timeline: auto, auto !important; }"
|
|
13560
|
+
].join("\n");
|
|
13561
|
+
Object.entries(AUTHORING_CODES).filter(([, entry]) => entry.kind === "suggested").map(([code]) => code);
|
|
13562
|
+
var URL_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
|
|
13563
|
+
/** A page target that is really a URL: the one reading of `mailto:`/`https:` a page-mode link can never mean. */
|
|
13564
|
+
var isUrlTarget = (target) => typeof target === "string" && !e$7(target) && URL_SCHEME.test(target);
|
|
13565
|
+
var isRoot = (element) => !element.definition.parentId;
|
|
13566
|
+
var stepsOf$1 = (element) => Object.values(element.definition.interactions ?? {});
|
|
13719
13567
|
/**
|
|
13720
|
-
*
|
|
13721
|
-
*
|
|
13568
|
+
* A key the element or step does not take, renamed to the one it was a typo of — when that one is free — or dropped:
|
|
13569
|
+
* it was never read, so dropping it changes nothing on screen.
|
|
13722
13570
|
*/
|
|
13723
|
-
var
|
|
13724
|
-
const
|
|
13725
|
-
|
|
13726
|
-
const
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
|
|
13730
|
-
|
|
13731
|
-
|
|
13732
|
-
|
|
13733
|
-
|
|
13734
|
-
|
|
13735
|
-
|
|
13736
|
-
|
|
13737
|
-
|
|
13571
|
+
var settleUnknownKeys = (record, known, what, on, report, defaults = {}) => {
|
|
13572
|
+
for (const key of Object.keys(record)) {
|
|
13573
|
+
if (known.includes(key)) continue;
|
|
13574
|
+
const wrapped = record[key];
|
|
13575
|
+
if (e$33(wrapped) && Object.keys(wrapped).length > 0 && Object.keys(wrapped).every((inner) => known.includes(inner))) {
|
|
13576
|
+
const inners = Object.keys(wrapped);
|
|
13577
|
+
if (inners.every((inner) => record[inner] === void 0 || record[inner] === defaults[inner])) {
|
|
13578
|
+
Object.assign(record, wrapped);
|
|
13579
|
+
Reflect.deleteProperty(record, key);
|
|
13580
|
+
report(`Moved ${inners.join(", ")} out of the ${what} "${key}", up to where ${inners.length === 1 ? "it is" : "they are"} read.`, {
|
|
13581
|
+
on,
|
|
13582
|
+
op: "unwrap",
|
|
13583
|
+
key
|
|
13584
|
+
});
|
|
13585
|
+
}
|
|
13586
|
+
continue;
|
|
13587
|
+
}
|
|
13588
|
+
const meant = closest$1(key, known);
|
|
13589
|
+
if (meant !== void 0 && record[meant] === void 0) {
|
|
13590
|
+
record[meant] = record[key];
|
|
13591
|
+
report(`Renamed the ${what} "${key}" to "${meant}".`, {
|
|
13592
|
+
on,
|
|
13593
|
+
op: "rename",
|
|
13594
|
+
key,
|
|
13595
|
+
to: meant
|
|
13596
|
+
});
|
|
13597
|
+
} else report(`Removed the ${what} "${key}", which nothing reads.`, {
|
|
13598
|
+
on,
|
|
13599
|
+
op: "remove",
|
|
13600
|
+
key
|
|
13601
|
+
});
|
|
13602
|
+
Reflect.deleteProperty(record, key);
|
|
13603
|
+
}
|
|
13738
13604
|
};
|
|
13739
|
-
|
|
13740
|
-
|
|
13741
|
-
|
|
13742
|
-
|
|
13743
|
-
|
|
13744
|
-
|
|
13745
|
-
};
|
|
13605
|
+
/** A flag written as the words `'true'`/`'false'`, stored as the boolean it is read as. */
|
|
13606
|
+
var asFlag = (value) => value === "true" ? true : value === "false" ? false : void 0;
|
|
13607
|
+
var stepSpec = (catalogs, step) => {
|
|
13608
|
+
const vocabulary = catalogs.vocabulary;
|
|
13609
|
+
const table = step.type === "globalCallback" ? vocabulary?.globalCallbacks : step.type === "utility" ? vocabulary?.utilities : step.type === "callback" ? vocabulary?.sharedCallbacks : void 0;
|
|
13610
|
+
return table && Object.hasOwn(table, step.action) ? table[step.action] : void 0;
|
|
13746
13611
|
};
|
|
13747
|
-
|
|
13748
|
-
|
|
13749
|
-
|
|
13750
|
-
|
|
13751
|
-
|
|
13752
|
-
|
|
13753
|
-
|
|
13754
|
-
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
13759
|
-
|
|
13760
|
-
|
|
13761
|
-
|
|
13762
|
-
|
|
13763
|
-
|
|
13764
|
-
|
|
13765
|
-
|
|
13766
|
-
|
|
13767
|
-
|
|
13768
|
-
|
|
13769
|
-
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
13774
|
-
const
|
|
13775
|
-
for (const [
|
|
13776
|
-
const
|
|
13777
|
-
if (
|
|
13778
|
-
|
|
13779
|
-
value
|
|
13780
|
-
|
|
13781
|
-
|
|
13612
|
+
new Set(Object.keys({
|
|
13613
|
+
"page-target-url": (element, _ctx, report) => {
|
|
13614
|
+
const { href, mode } = element.attributes;
|
|
13615
|
+
if (element.definition.type === "link" && (mode ?? "page") === "page" && isUrlTarget(href)) {
|
|
13616
|
+
element.attributes.mode = "external";
|
|
13617
|
+
report(`The link to "${href}" now opens it as an external URL.`, {
|
|
13618
|
+
on: "attribute",
|
|
13619
|
+
op: "set",
|
|
13620
|
+
key: "mode",
|
|
13621
|
+
value: "external"
|
|
13622
|
+
});
|
|
13623
|
+
}
|
|
13624
|
+
for (const step of stepsOf$1(element)) if (step.action === "navigate" && step.params.urlType === "page" && isUrlTarget(step.params.url)) {
|
|
13625
|
+
step.params.urlType = "external";
|
|
13626
|
+
report(`Step "${step.id}" now navigates to "${step.params.url}" as an external URL.`, {
|
|
13627
|
+
on: { step: step.id },
|
|
13628
|
+
op: "set",
|
|
13629
|
+
key: "urlType",
|
|
13630
|
+
value: "external"
|
|
13631
|
+
});
|
|
13632
|
+
}
|
|
13633
|
+
},
|
|
13634
|
+
"unknown-attribute": (element, ctx, report) => {
|
|
13635
|
+
const names = ctx.attributeNamesFor(element);
|
|
13636
|
+
if (!isRoot(element) && names) settleUnknownKeys(element.attributes, names, "attribute", "attribute", report, ctx.defaultsFor(element));
|
|
13637
|
+
},
|
|
13638
|
+
"attribute-kind": (element, ctx, report) => {
|
|
13639
|
+
const defaults = ctx.catalogs.defaultAttributes?.[element.definition.type] ?? {};
|
|
13640
|
+
for (const [name, value] of Object.entries(element.attributes)) {
|
|
13641
|
+
const flag = asFlag(value);
|
|
13642
|
+
if (typeof defaults[name] === "boolean" && flag !== void 0) {
|
|
13643
|
+
element.attributes[name] = flag;
|
|
13644
|
+
report(`\`${name}\` is now the boolean ${String(flag)}, not the text "${String(value)}".`, {
|
|
13645
|
+
on: "attribute",
|
|
13646
|
+
op: "set",
|
|
13647
|
+
key: name,
|
|
13648
|
+
value: flag
|
|
13649
|
+
});
|
|
13650
|
+
}
|
|
13651
|
+
}
|
|
13652
|
+
},
|
|
13653
|
+
"step-params": (element, ctx, report) => {
|
|
13654
|
+
for (const step of stepsOf$1(element)) {
|
|
13655
|
+
const spec = stepSpec(ctx.catalogs, step);
|
|
13656
|
+
if (!spec?.params) continue;
|
|
13657
|
+
const params = spec.params;
|
|
13658
|
+
if (spec.strictParams) settleUnknownKeys(step.params, Object.keys(params), `param of step "${step.id}"`, { step: step.id }, report);
|
|
13659
|
+
for (const [key, value] of Object.entries(step.params)) {
|
|
13660
|
+
const flag = asFlag(value);
|
|
13661
|
+
if (Object.hasOwn(params, key) && params[key].type === "boolean" && flag !== void 0) {
|
|
13662
|
+
step.params[key] = flag;
|
|
13663
|
+
report(`Step "${step.id}": \`${key}\` is now the boolean ${String(flag)}.`, {
|
|
13664
|
+
on: { step: step.id },
|
|
13665
|
+
op: "set",
|
|
13666
|
+
key,
|
|
13667
|
+
value: flag
|
|
13668
|
+
});
|
|
13669
|
+
}
|
|
13670
|
+
}
|
|
13671
|
+
}
|
|
13672
|
+
},
|
|
13673
|
+
"global-callback-module": (element, ctx, report) => {
|
|
13674
|
+
for (const step of stepsOf$1(element)) {
|
|
13675
|
+
const declared = step.type === "globalCallback" && ctx.catalogs.vocabulary ? ctx.catalogs.vocabulary.globalCallbacks[step.action] : void 0;
|
|
13676
|
+
if (declared && step.elementId !== declared.source) {
|
|
13677
|
+
step.elementId = declared.source;
|
|
13678
|
+
report(`Step "${step.id}" now runs "${step.action}" on "${declared.source}", the module that registers it.`, {
|
|
13679
|
+
on: { step: step.id },
|
|
13680
|
+
op: "set",
|
|
13681
|
+
key: "on",
|
|
13682
|
+
value: declared.source
|
|
13683
|
+
});
|
|
13684
|
+
}
|
|
13685
|
+
}
|
|
13686
|
+
},
|
|
13687
|
+
"utility-module": (element, ctx, report) => {
|
|
13688
|
+
for (const step of stepsOf$1(element)) {
|
|
13689
|
+
const known = ctx.catalogs.vocabulary ? Object.hasOwn(ctx.catalogs.vocabulary.utilities, step.action) : false;
|
|
13690
|
+
if (step.type === "utility" && known && step.elementId !== null) {
|
|
13691
|
+
step.elementId = null;
|
|
13692
|
+
report(`Step "${step.id}" runs the utility "${step.action}" on no element: a utility takes none.`, {
|
|
13693
|
+
on: { step: step.id },
|
|
13694
|
+
op: "remove",
|
|
13695
|
+
key: "on"
|
|
13696
|
+
});
|
|
13697
|
+
}
|
|
13698
|
+
}
|
|
13699
|
+
},
|
|
13700
|
+
"visibility-as-attribute": (element, _ctx, report) => {
|
|
13701
|
+
const bindings = element.definition.bindings;
|
|
13702
|
+
const moved = bindings?.attributes?.filter((binding) => binding.to === "visibility") ?? [];
|
|
13703
|
+
if (!bindings || moved.length === 0) return;
|
|
13704
|
+
bindings.attributes = bindings.attributes?.filter((binding) => binding.to !== "visibility");
|
|
13705
|
+
bindings.initialState = [...bindings.initialState ?? [], ...moved];
|
|
13706
|
+
report("The visibility binding now sets the visibility, rather than an attribute nothing reads.");
|
|
13707
|
+
},
|
|
13708
|
+
"binding-target-unknown": (element, ctx, report) => {
|
|
13709
|
+
const names = ctx.attributeNamesFor(element);
|
|
13710
|
+
const bindings = element.definition.bindings;
|
|
13711
|
+
if (!names || !bindings?.attributes) return;
|
|
13712
|
+
const reads = (binding) => binding.to === "visibility" || binding.to === "className" || names.includes(binding.to);
|
|
13713
|
+
for (const binding of bindings.attributes.filter((candidate) => !reads(candidate))) report(`Removed the binding onto "${binding.to}", which a "${element.definition.type}" never reads.`, {
|
|
13714
|
+
on: "binding",
|
|
13715
|
+
op: "remove",
|
|
13716
|
+
key: binding.to
|
|
13717
|
+
});
|
|
13718
|
+
bindings.attributes = bindings.attributes.filter(reads);
|
|
13719
|
+
},
|
|
13720
|
+
"unknown-transformer": (element, ctx, report) => {
|
|
13721
|
+
const catalog = ctx.catalogs.transformers;
|
|
13722
|
+
if (!catalog) return;
|
|
13723
|
+
for (const binding of Object.values(element.definition.bindings ?? {}).flat()) for (const transformer of binding.transformers ?? []) {
|
|
13724
|
+
const meant = Object.hasOwn(catalog, transformer.action) ? void 0 : closest$1(transformer.action, Object.keys(catalog));
|
|
13725
|
+
if (meant !== void 0) {
|
|
13726
|
+
report(`The binding of "${binding.to}" now runs "${meant}" (was "${transformer.action}").`, {
|
|
13727
|
+
on: "binding",
|
|
13728
|
+
op: "replace",
|
|
13729
|
+
key: transformer.action,
|
|
13730
|
+
to: meant
|
|
13731
|
+
});
|
|
13732
|
+
transformer.action = meant;
|
|
13733
|
+
}
|
|
13734
|
+
}
|
|
13735
|
+
},
|
|
13736
|
+
"list-items-ignored": (element, _ctx, report) => {
|
|
13737
|
+
const { attributes } = element;
|
|
13738
|
+
const bound = Object.values(element.definition.bindings ?? {}).flat().some((binding) => binding.to === "items");
|
|
13739
|
+
const written = Array.isArray(attributes.items) && attributes.items.length > 0;
|
|
13740
|
+
if (element.definition.type === "list" && attributes.source !== "controlled" && (bound || written)) {
|
|
13741
|
+
attributes.source = "controlled";
|
|
13742
|
+
report("The list now reads its items (`source: controlled`), one row per item.", {
|
|
13743
|
+
on: "attribute",
|
|
13744
|
+
op: "set",
|
|
13745
|
+
key: "source",
|
|
13746
|
+
value: "controlled"
|
|
13782
13747
|
});
|
|
13783
13748
|
}
|
|
13784
|
-
}
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
|
|
13788
|
-
|
|
13789
|
-
|
|
13790
|
-
|
|
13791
|
-
|
|
13792
|
-
|
|
13793
|
-
|
|
13794
|
-
|
|
13795
|
-
|
|
13796
|
-
|
|
13797
|
-
|
|
13798
|
-
|
|
13799
|
-
|
|
13800
|
-
|
|
13801
|
-
|
|
13802
|
-
|
|
13803
|
-
|
|
13804
|
-
|
|
13805
|
-
} : {
|
|
13806
|
-
...ancestor,
|
|
13807
|
-
css
|
|
13749
|
+
},
|
|
13750
|
+
"list-row-not-li": (element, ctx, report) => {
|
|
13751
|
+
const { parentId } = element.definition;
|
|
13752
|
+
const list = parentId ? ctx.element(parentId) : void 0;
|
|
13753
|
+
if (list?.definition.type === "list" && list.attributes.source === "controlled" && isPlainContainer(element)) {
|
|
13754
|
+
element.attributes.subType = "li";
|
|
13755
|
+
report("The row is now an `<li>` (`subType: li`), an item of the list it renders in.", {
|
|
13756
|
+
on: "attribute",
|
|
13757
|
+
op: "set",
|
|
13758
|
+
key: "subType",
|
|
13759
|
+
value: "li"
|
|
13760
|
+
});
|
|
13761
|
+
}
|
|
13762
|
+
},
|
|
13763
|
+
"overlay-starts-open": (element, _ctx, report) => {
|
|
13764
|
+
const { type, bindings } = element.definition;
|
|
13765
|
+
const visibilityBound = (bindings?.initialState ?? []).some((binding) => binding.to === "visibility");
|
|
13766
|
+
if ((type === "modalContainer" || type === "dialogContainer") && element.definition.initialState?.visibility !== false && !visibilityBound) {
|
|
13767
|
+
element.definition.initialState = {
|
|
13768
|
+
...element.definition.initialState,
|
|
13769
|
+
visibility: false
|
|
13808
13770
|
};
|
|
13809
|
-
|
|
13771
|
+
report(`The ${type} now starts closed, to be opened from a flow.`, {
|
|
13772
|
+
on: "field",
|
|
13773
|
+
op: "set",
|
|
13774
|
+
key: "visible",
|
|
13775
|
+
value: false
|
|
13776
|
+
});
|
|
13777
|
+
}
|
|
13778
|
+
},
|
|
13779
|
+
"state-key-has-runtime-prefix": (element, _ctx, report) => {
|
|
13780
|
+
for (const step of stepsOf$1(element)) {
|
|
13781
|
+
if (step.type !== "globalCallback" || step.elementId !== "state") continue;
|
|
13782
|
+
for (const param of STATE_PATH_PARAMS[step.action] ?? []) {
|
|
13783
|
+
const value = step.params[param];
|
|
13784
|
+
if (typeof value === "string" && /^(?:runtime\.)?state\./.test(value)) {
|
|
13785
|
+
const next = value.replace(/^(?:runtime\.)?state\./, "");
|
|
13786
|
+
step.params[param] = next;
|
|
13787
|
+
report(`Step "${step.id}": \`${param}\` is now "${next}" (was "${value}").`, {
|
|
13788
|
+
on: { step: step.id },
|
|
13789
|
+
op: "set",
|
|
13790
|
+
key: param,
|
|
13791
|
+
value: next
|
|
13792
|
+
});
|
|
13793
|
+
}
|
|
13794
|
+
}
|
|
13810
13795
|
}
|
|
13811
13796
|
}
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
13797
|
+
}));
|
|
13798
|
+
var e$4 = ".Toastify__toast-container.plitzi-sdk-toasts";
|
|
13799
|
+
var t$4 = [
|
|
13800
|
+
{
|
|
13801
|
+
selector: e$4,
|
|
13802
|
+
fields: {
|
|
13803
|
+
background: ["--toastify-color-light", "--toastify-color-dark"],
|
|
13804
|
+
text: ["--toastify-text-color-light", "--toastify-text-color-dark"],
|
|
13805
|
+
success: ["--toastify-color-success"],
|
|
13806
|
+
danger: ["--toastify-color-error"],
|
|
13807
|
+
warning: ["--toastify-color-warning"],
|
|
13808
|
+
info: ["--toastify-color-info"],
|
|
13809
|
+
radius: ["--toastify-toast-bd-radius"],
|
|
13810
|
+
font: ["--toastify-font-family"],
|
|
13811
|
+
shadow: ["--toastify-toast-shadow"],
|
|
13812
|
+
padding: ["--toastify-toast-padding"],
|
|
13813
|
+
minHeight: ["--toastify-toast-min-height"]
|
|
13814
|
+
}
|
|
13815
|
+
},
|
|
13816
|
+
{
|
|
13817
|
+
selector: `:where(${e$4} .Toastify__toast)`,
|
|
13818
|
+
fields: {
|
|
13819
|
+
fontSize: ["font-size"],
|
|
13820
|
+
fontWeight: ["font-weight"],
|
|
13821
|
+
lineHeight: ["line-height"],
|
|
13822
|
+
border: ["border"]
|
|
13823
|
+
}
|
|
13824
|
+
},
|
|
13825
|
+
{
|
|
13826
|
+
selector: `${e$4} .Toastify__toast-icon`,
|
|
13827
|
+
fields: {
|
|
13828
|
+
iconSize: ["width"],
|
|
13829
|
+
iconGap: ["margin-inline-end"]
|
|
13830
|
+
}
|
|
13831
|
+
},
|
|
13832
|
+
{
|
|
13833
|
+
selector: `${e$4} .Toastify__close-button`,
|
|
13834
|
+
fields: { closeColor: ["color"] }
|
|
13835
|
+
},
|
|
13836
|
+
{
|
|
13837
|
+
selector: `${e$4} .Toastify__close-button:not(:hover, :focus)`,
|
|
13838
|
+
fields: { closeOpacity: ["opacity"] }
|
|
13839
|
+
},
|
|
13840
|
+
{
|
|
13841
|
+
selector: `${e$4} .Toastify__progress-bar--wrp`,
|
|
13842
|
+
fields: { progressHeight: ["height"] }
|
|
13843
|
+
}
|
|
13844
|
+
];
|
|
13845
|
+
var n$4 = t$4.flatMap((e) => Object.keys(e.fields));
|
|
13846
|
+
var r$2$1 = (e) => n$4.includes(e);
|
|
13847
|
+
n$4.filter(r$2$1);
|
|
13848
|
+
var c$2$1 = (e) => e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13849
|
+
t$4.map((e) => {
|
|
13850
|
+
let t = new Map(Object.entries(e.fields).flatMap(([e, t]) => r$2$1(e) ? t.map((t) => [t, e]) : []));
|
|
13851
|
+
return {
|
|
13852
|
+
pattern: RegExp(`(?:^|\\n)${c$2$1(e.selector)}\\s*\\{([^}]*)\\}`, "g"),
|
|
13853
|
+
fieldOf: (e) => t.get(e)
|
|
13854
|
+
};
|
|
13855
|
+
});
|
|
13856
|
+
Object.fromEntries(e$30.map((e) => [e, t$26(e)]));
|
|
13815
13857
|
[...new Set(STYLE_STATES.filter((state) => state !== "hidden"))].filter((state) => u$7(state) !== `:${state}`);
|
|
13816
13858
|
new Set("break case catch class const continue debugger default delete do else enum export extends false finally for function if import in instanceof new null return super switch this throw true try typeof var void while with yield let static implements interface package private protected public await element styles".split(" "));
|
|
13817
13859
|
new Set(STYLE_STATES);
|
|
@@ -15275,7 +15317,7 @@ var pluginDeclarations = async (folder) => {
|
|
|
15275
15317
|
}));
|
|
15276
15318
|
};
|
|
15277
15319
|
/** The manifest of a plugin run as it was built, read; nothing when it cannot be — the layout check says why first. */
|
|
15278
|
-
var manifestOf$
|
|
15320
|
+
var manifestOf$2 = (file) => {
|
|
15279
15321
|
try {
|
|
15280
15322
|
const manifest = JSON.parse(readFileSync(file, "utf-8"));
|
|
15281
15323
|
return e$33(manifest) ? manifest : {};
|
|
@@ -15288,7 +15330,7 @@ var manifestOf$1 = (file) => {
|
|
|
15288
15330
|
* space): each folder's type and every element its manifest provides (`pluginSchema`). None in most projects.
|
|
15289
15331
|
*/
|
|
15290
15332
|
var builtPluginTypes = (folder) => existsSync(folder) ? readdirSync(folder, { withFileTypes: true }).filter((entry) => entry.isDirectory()).sort((a, b) => a.name.localeCompare(b.name)).flatMap((entry) => {
|
|
15291
|
-
const { pluginSchema } = manifestOf$
|
|
15333
|
+
const { pluginSchema } = manifestOf$2(path.join(folder, entry.name, d$1));
|
|
15292
15334
|
return [entry.name, ...e$33(pluginSchema) ? Object.keys(pluginSchema) : []];
|
|
15293
15335
|
}) : [];
|
|
15294
15336
|
/**
|
|
@@ -18725,7 +18767,7 @@ var momentChanges = (before, after, state) => {
|
|
|
18725
18767
|
...stateChanges
|
|
18726
18768
|
];
|
|
18727
18769
|
};
|
|
18728
|
-
var selectorOf
|
|
18770
|
+
var selectorOf = (authored, id) => authored && Object.hasOwn(authored.handles.elements, id) ? authored.handles.elements[id].selector : `[data-plitzi-el="${id}"]`;
|
|
18729
18771
|
var FIELDS = "input, textarea, select";
|
|
18730
18772
|
/** The elements of the space the fields inside a node belong to: the nearest element around each. */
|
|
18731
18773
|
var fieldOwnersInPage = (node, selector) => Array.from(node.querySelectorAll(selector), (field) => field.closest("[data-plitzi-el]")?.getAttribute("data-plitzi-el")).map((owner) => owner ?? "?");
|
|
@@ -18735,7 +18777,7 @@ var fieldOwnersInPage = (node, selector) => Array.from(node.querySelectorAll(sel
|
|
|
18735
18777
|
* it is another's; or what could not be filled, and why.
|
|
18736
18778
|
*/
|
|
18737
18779
|
var fillField = async (page, authored, { element, value }) => {
|
|
18738
|
-
const node = page.locator(selectorOf
|
|
18780
|
+
const node = page.locator(selectorOf(authored, element)).first();
|
|
18739
18781
|
if (await node.count() === 0) return { problem: `no element ${element} is on this page to fill` };
|
|
18740
18782
|
const own = await node.evaluate((each, selector) => each.matches(selector), FIELDS);
|
|
18741
18783
|
const owners = own ? [element] : await node.evaluate(fieldOwnersInPage, FIELDS);
|
|
@@ -18760,7 +18802,7 @@ var fillField = async (page, authored, { element, value }) => {
|
|
|
18760
18802
|
* nothing is said as such: a button whose flow does nothing looks the same as one that works until somebody clicks.
|
|
18761
18803
|
*/
|
|
18762
18804
|
var clickEffects = async (page, authored, { element: id, fill }) => {
|
|
18763
|
-
const target = page.locator(selectorOf
|
|
18805
|
+
const target = page.locator(selectorOf(authored, id)).first();
|
|
18764
18806
|
if (await target.count() === 0) return {
|
|
18765
18807
|
element: id,
|
|
18766
18808
|
problem: `no element ${id} is on this page`,
|
|
@@ -18889,12 +18931,12 @@ var lateElements = (schema, served, hydrated, width) => {
|
|
|
18889
18931
|
browserOnly
|
|
18890
18932
|
};
|
|
18891
18933
|
};
|
|
18892
|
-
var checkAt = async (browser, origin, pathname, width,
|
|
18934
|
+
var checkAt = async (browser, origin, pathname, width, view, authored, asked, ssr, account, click) => {
|
|
18893
18935
|
const handles = authored?.handles;
|
|
18894
18936
|
const page = await openProjectPage(browser, origin, {
|
|
18895
18937
|
width,
|
|
18896
18938
|
height: 900,
|
|
18897
|
-
...
|
|
18939
|
+
...view
|
|
18898
18940
|
});
|
|
18899
18941
|
/** A report of a page that could not be looked at — nothing answered, no sign-in, sent elsewhere. */
|
|
18900
18942
|
const unchecked = (issue) => ({
|
|
@@ -19125,6 +19167,7 @@ var check = async (routes, options) => {
|
|
|
19125
19167
|
asked,
|
|
19126
19168
|
ssr: Boolean(options.ssr),
|
|
19127
19169
|
...options.scheme ? { scheme: options.scheme } : {},
|
|
19170
|
+
presence: options.presence === true,
|
|
19128
19171
|
...account ? { account } : {},
|
|
19129
19172
|
...options.click ? { click: {
|
|
19130
19173
|
element: options.click,
|
|
@@ -19154,7 +19197,10 @@ var checkRoutes = async (project, routes, options) => {
|
|
|
19154
19197
|
try {
|
|
19155
19198
|
const reports = [];
|
|
19156
19199
|
for (const route of routes) for (const width of options.widths) {
|
|
19157
|
-
const report = await checkAt(browser, where.origin, route, width,
|
|
19200
|
+
const report = await checkAt(browser, where.origin, route, width, {
|
|
19201
|
+
...options.scheme ? { scheme: options.scheme } : {},
|
|
19202
|
+
presence: options.presence === true
|
|
19203
|
+
}, authored, options.asked, options.ssr, options.account, options.click);
|
|
19158
19204
|
reports.push({
|
|
19159
19205
|
...report,
|
|
19160
19206
|
...options.scheme ? { scheme: options.scheme } : {}
|
|
@@ -19397,16 +19443,6 @@ var projectRunner = async (root) => {
|
|
|
19397
19443
|
} catch {}
|
|
19398
19444
|
fail("plitzi functions dev runs them with this project’s own @plitzi/sdk-server, and the isolates it needs:\n npm install --save-dev @plitzi/sdk-server isolated-vm core-js");
|
|
19399
19445
|
};
|
|
19400
|
-
/** `PLITZI_FUNCTIONS_CREDENTIALS`, a JSON object of credential id → its keys: what `ctx.fetch` may name locally. */
|
|
19401
|
-
var localCredentials = () => {
|
|
19402
|
-
const raw = process.env.PLITZI_FUNCTIONS_CREDENTIALS;
|
|
19403
|
-
try {
|
|
19404
|
-
const value = raw ? JSON.parse(raw) : {};
|
|
19405
|
-
return e$3(value) ? Object.fromEntries(Object.entries(value).flatMap(([id, keys]) => e$3(keys) ? [[id, Object.fromEntries(Object.entries(keys).filter((pair) => typeof pair[1] === "string"))]] : [])) : {};
|
|
19406
|
-
} catch {
|
|
19407
|
-
return {};
|
|
19408
|
-
}
|
|
19409
|
-
};
|
|
19410
19446
|
var NO_NODE_SNAPSHOT = "--no-node-snapshot";
|
|
19411
19447
|
/**
|
|
19412
19448
|
* The isolates `dev` runs need Node's startup snapshot off, and a process cannot turn it off once started: `dev` runs
|
|
@@ -19436,10 +19472,7 @@ var devFunction = async (task, options) => {
|
|
|
19436
19472
|
const root = params && await rootOf();
|
|
19437
19473
|
const runner = root ? await projectRunner(root) : void 0;
|
|
19438
19474
|
if (!root || !runner) return;
|
|
19439
|
-
const local = runner.createLocalFunctions({
|
|
19440
|
-
credentials: localCredentials(),
|
|
19441
|
-
dataDir: path.join(root, m)
|
|
19442
|
-
});
|
|
19475
|
+
const local = runner.createLocalFunctions({ dataDir: path.join(root, m) });
|
|
19443
19476
|
const run = async () => {
|
|
19444
19477
|
const loaded = await local.load(await readFunctionsFiles(root));
|
|
19445
19478
|
if (!loaded.ok) {
|
|
@@ -21204,6 +21237,125 @@ var fix = async (options) => {
|
|
|
21204
21237
|
].join("\n"));
|
|
21205
21238
|
};
|
|
21206
21239
|
//#endregion
|
|
21240
|
+
//#region src/commands/functionsAdd.ts
|
|
21241
|
+
/** Where a package added to the functions is kept: their own code from then on, copied in. */
|
|
21242
|
+
var VENDOR_DIR = "vendor";
|
|
21243
|
+
/** What a space's functions may weigh built, whole — a package added is part of it (`@plitzi/sdk-server`'s cap). */
|
|
21244
|
+
var MAX_FUNCTIONS_BYTES = 1e6;
|
|
21245
|
+
/** A package's name, as npm writes one: `ical.js`, `@scope/name`. */
|
|
21246
|
+
var PACKAGE_NAME = /^(@[a-z0-9][\w.-]*\/)?[a-z0-9][\w.-]*$/i;
|
|
21247
|
+
/** Globals of Node a package may read and a runner does not have: said, since a bundle cannot tell if they run. */
|
|
21248
|
+
var NODE_GLOBALS = /\b(process\.(env|nextTick|platform|versions?)|Buffer\.(from|alloc|isBuffer)|__dirname|__filename)\b/;
|
|
21249
|
+
/** The file a package is kept in, under `src/functions/vendor/`: its name, with its scope folded in. */
|
|
21250
|
+
var vendorFileOf = (name) => `${name.replace(/^@/, "").replace("/", "__")}.js`;
|
|
21251
|
+
/** The package's own `package.json`, found from where it resolves: its version and its licence for the header. */
|
|
21252
|
+
var manifestOf$1 = async (entry, name) => {
|
|
21253
|
+
for (let dir = path.dirname(entry); dir !== path.dirname(dir); dir = path.dirname(dir)) try {
|
|
21254
|
+
const parsed = JSON.parse(await fs.readFile(path.join(dir, "package.json"), "utf8"));
|
|
21255
|
+
if (e$3(parsed) && parsed.name === name) return {
|
|
21256
|
+
version: typeof parsed.version === "string" ? parsed.version : "?",
|
|
21257
|
+
license: typeof parsed.license === "string" ? parsed.license : "no licence stated"
|
|
21258
|
+
};
|
|
21259
|
+
} catch {}
|
|
21260
|
+
return {
|
|
21261
|
+
version: "?",
|
|
21262
|
+
license: "no licence stated"
|
|
21263
|
+
};
|
|
21264
|
+
};
|
|
21265
|
+
/**
|
|
21266
|
+
* One package bundled for the functions: web APIs only, as they run — what reaches Node (`fs`, `node:crypto`) does
|
|
21267
|
+
* not resolve on a neutral platform, and is the reason it is refused. With what it exports, for its types.
|
|
21268
|
+
*/
|
|
21269
|
+
var bundle = async (root, name, withDefault) => {
|
|
21270
|
+
try {
|
|
21271
|
+
const result = await build({
|
|
21272
|
+
stdin: {
|
|
21273
|
+
contents: `export * from '${name}';${withDefault ? `\nexport { default } from '${name}';` : ""}`,
|
|
21274
|
+
resolveDir: root,
|
|
21275
|
+
loader: "js"
|
|
21276
|
+
},
|
|
21277
|
+
bundle: true,
|
|
21278
|
+
write: false,
|
|
21279
|
+
metafile: true,
|
|
21280
|
+
format: "esm",
|
|
21281
|
+
platform: "neutral",
|
|
21282
|
+
mainFields: ["module", "main"],
|
|
21283
|
+
target: "es2022",
|
|
21284
|
+
minify: true,
|
|
21285
|
+
legalComments: "inline",
|
|
21286
|
+
logLevel: "silent"
|
|
21287
|
+
});
|
|
21288
|
+
const exports = Object.values(result.metafile.outputs).flatMap((output) => output.exports);
|
|
21289
|
+
return {
|
|
21290
|
+
code: result.outputFiles.map((output) => output.text).join(""),
|
|
21291
|
+
exports
|
|
21292
|
+
};
|
|
21293
|
+
} catch (error) {
|
|
21294
|
+
return { errors: e$3(error) && Array.isArray(error.errors) ? error.errors.flatMap((entry) => e$3(entry) && typeof entry.text === "string" ? [{ text: entry.text }] : []) : [{ text: error instanceof Error ? error.message : String(error) }] };
|
|
21295
|
+
}
|
|
21296
|
+
};
|
|
21297
|
+
/** Why esbuild could not bundle it, in the words that say what to do: a Node module is a package that cannot run here. */
|
|
21298
|
+
var refusalOf$1 = (name, errors) => {
|
|
21299
|
+
const node = errors.map((entry) => /Could not resolve "([^"]+)"/.exec(entry.text)?.[1]).find((module) => module !== void 0 && !module.startsWith("."));
|
|
21300
|
+
return node ? `${name} reaches "${node}", which the functions do not have: they run with web APIs only — fetch, crypto.subtle, URL — on any runner, so a package that needs Node cannot run there. Look for one written for the browser or the edge.` : `${name} could not be bundled: ${errors.map((entry) => entry.text).join("; ")}`;
|
|
21301
|
+
};
|
|
21302
|
+
/**
|
|
21303
|
+
* `plitzi functions add <package>`: a package the functions use, as a function carries its dependencies — bundled into
|
|
21304
|
+
* `src/functions/vendor/`, and from then on their own code: pushed and built with the rest, read by the builder, run by
|
|
21305
|
+
* the runner. Nothing is resolved anywhere else, so a space's functions stay its own files. Installed first, with the
|
|
21306
|
+
* project's package manager, so its version is the project's choice and its types reach the editor.
|
|
21307
|
+
*/
|
|
21308
|
+
var addFunctionsPackage = async (name, options) => {
|
|
21309
|
+
if (!PACKAGE_NAME.test(name)) {
|
|
21310
|
+
fail(`"${name}" is not a package's name — ical.js, @scope/name.`);
|
|
21311
|
+
return;
|
|
21312
|
+
}
|
|
21313
|
+
const root = (await projectHere("whose functions these are"))?.root;
|
|
21314
|
+
if (!root) return;
|
|
21315
|
+
let entry;
|
|
21316
|
+
try {
|
|
21317
|
+
entry = createRequire(path.join(root, "package.json")).resolve(name);
|
|
21318
|
+
} catch {
|
|
21319
|
+
try {
|
|
21320
|
+
entry = createRequire(path.join(root, "package.json")).resolve(`${name}/package.json`);
|
|
21321
|
+
} catch {
|
|
21322
|
+
fail(`${name} is not installed in this project: install it first (npm install --save-dev ${name}), then add it.`);
|
|
21323
|
+
return;
|
|
21324
|
+
}
|
|
21325
|
+
}
|
|
21326
|
+
let built = await bundle(root, name, true);
|
|
21327
|
+
if ("errors" in built && built.errors.some((entry) => /No matching export .*"default"/.test(entry.text))) built = await bundle(root, name, false);
|
|
21328
|
+
if ("errors" in built) {
|
|
21329
|
+
fail(refusalOf$1(name, built.errors));
|
|
21330
|
+
return;
|
|
21331
|
+
}
|
|
21332
|
+
const bytes = Buffer.byteLength(built.code);
|
|
21333
|
+
if (bytes > MAX_FUNCTIONS_BYTES) {
|
|
21334
|
+
fail(`${name} is ${String(Math.round(bytes / 1024))} KB bundled, and a space's functions are at most ${String(MAX_FUNCTIONS_BYTES / 1e3)} KB built, all of it: look for a smaller one, or import less of it.`);
|
|
21335
|
+
return;
|
|
21336
|
+
}
|
|
21337
|
+
const { version, license } = await manifestOf$1(entry, name);
|
|
21338
|
+
const file = vendorFileOf(name);
|
|
21339
|
+
const relative = `./${VENDOR_DIR}/${file}`;
|
|
21340
|
+
const header = `// ${name}@${version} — ${license}. Added by \`plitzi functions add ${name}\`: the package bundled for the functions\n// (web APIs only), imported as '${relative}'. Not to be edited: run it again to update it.\n`;
|
|
21341
|
+
const types = `// The types of ${name}@${version}, for '${relative}' — the installed package's own.\n${built.exports.filter((exported) => exported !== "default").length > 0 ? `export * from '${name}';\n` : ""}${built.exports.includes("default") ? `export { default } from '${name}';\n` : ""}`;
|
|
21342
|
+
const written = {
|
|
21343
|
+
[path.join(VENDOR_DIR, file)]: `${header}${built.code}`,
|
|
21344
|
+
[path.join(VENDOR_DIR, file.replace(/\.js$/, ".d.ts"))]: types
|
|
21345
|
+
};
|
|
21346
|
+
const base = path.join(root, h$1);
|
|
21347
|
+
if (options.dryRun) {
|
|
21348
|
+
sayDryRun(`plitzi functions add ${name}`, [...(await filesWouldWrite(base, Object.keys(written))).map((line) => line.replace(/^(.) /, `$1 ${h$1}/`))]);
|
|
21349
|
+
return;
|
|
21350
|
+
}
|
|
21351
|
+
for (const [target, text] of Object.entries(written)) {
|
|
21352
|
+
await fs.mkdir(path.dirname(path.join(base, target)), { recursive: true });
|
|
21353
|
+
await fs.writeFile(path.join(base, target), text);
|
|
21354
|
+
}
|
|
21355
|
+
console.log(`Added ${name}@${version} (${String(Math.round(bytes / 1024))} KB) as ${h$1}/${VENDOR_DIR}/${file}: import it from a file of ${h$1}/ with '${relative}' — \`functions push\` saves it with the rest.`);
|
|
21356
|
+
if (NODE_GLOBALS.test(built.code)) console.warn(`${name} reads globals of Node (process, Buffer, __dirname) somewhere: the functions have none, so whatever reads them fails when it runs. Try what you use with \`plitzi functions dev\`.`);
|
|
21357
|
+
};
|
|
21358
|
+
//#endregion
|
|
21207
21359
|
//#region src/commands/siteOwnership.ts
|
|
21208
21360
|
var NOT_ASKED = (host) => `${host} is not served from this machine, so importing it takes proof that it is yours: its domain verified on one of your Plitzi spaces. That is asked of your Plitzi account, signing in — run it again with --account to ask. A site that is not yours is not imported.`;
|
|
21209
21361
|
var LOOPBACK = /^(127\.|::1$|::ffff:127\.)/;
|
|
@@ -23658,12 +23810,13 @@ var parseSteps = (script, every) => {
|
|
|
23658
23810
|
});
|
|
23659
23811
|
break;
|
|
23660
23812
|
case "type": {
|
|
23661
|
-
const
|
|
23662
|
-
|
|
23813
|
+
const quoted = /^(["'])(.+?)\1\s+(.+)$/s.exec(rest.join(" "));
|
|
23814
|
+
const [target, text] = quoted ? [quoted[2], quoted[3]] : [rest[0], rest.slice(1).join(" ")];
|
|
23815
|
+
if (!target || text === "") return { problem: `${at}: type needs an element and the text — type <element> <text>, type ".panel textarea" hi` };
|
|
23663
23816
|
steps.push({
|
|
23664
23817
|
kind: "type",
|
|
23665
23818
|
target,
|
|
23666
|
-
text: unquoted(
|
|
23819
|
+
text: unquoted(text)
|
|
23667
23820
|
});
|
|
23668
23821
|
break;
|
|
23669
23822
|
}
|
|
@@ -23733,12 +23886,42 @@ var TEXTS_SHOWN = 12;
|
|
|
23733
23886
|
var DRIFT_PX = 2;
|
|
23734
23887
|
/** An arrival that waits for the scroll and has not had it: one waiting to be seen, or one tied to the scroll. */
|
|
23735
23888
|
var WAITING_FOR_SCROLL = "[data-motion-on=\"view\"]:not([data-motion-seen]), [data-motion-on=\"scroll\"]";
|
|
23736
|
-
|
|
23737
|
-
|
|
23738
|
-
var
|
|
23739
|
-
|
|
23889
|
+
var BARE = /^[\w-]+$/;
|
|
23890
|
+
/** A bare word: an element's name — letters, digits, `-` and `_`, as an id is written — or else a tag (`textarea`). */
|
|
23891
|
+
var namedBy = (target) => `[data-plitzi-el="${target}"]`;
|
|
23892
|
+
/** What a wait waits for: an element by name or, a bare word naming none, a tag — whichever shows first. */
|
|
23893
|
+
var awaited = (target) => BARE.test(target) ? `${namedBy(target)}, ${target}` : target;
|
|
23894
|
+
/**
|
|
23895
|
+
* A target found on the page: an element's name, a tag no element is named by (`textarea`), or a selector — CSS or
|
|
23896
|
+
* Playwright's own (`button:has-text("Orbit")`, `text=Saved`, `role=button[name="Publish"]`). With how many it finds
|
|
23897
|
+
* (none is one not on the page), or why it is no selector at all: Playwright throws on one it cannot read, and an
|
|
23898
|
+
* uncaught throw ended the command with a stack trace.
|
|
23899
|
+
*/
|
|
23900
|
+
var targetOn = async (page, target) => {
|
|
23901
|
+
try {
|
|
23902
|
+
if (!BARE.test(target)) return {
|
|
23903
|
+
selector: target,
|
|
23904
|
+
found: await page.locator(target).first().count() > 0
|
|
23905
|
+
};
|
|
23906
|
+
if (await page.locator(namedBy(target)).first().count() > 0) return {
|
|
23907
|
+
selector: namedBy(target),
|
|
23908
|
+
found: true
|
|
23909
|
+
};
|
|
23910
|
+
return await page.locator(target).first().count() > 0 ? {
|
|
23911
|
+
selector: target,
|
|
23912
|
+
found: true
|
|
23913
|
+
} : {
|
|
23914
|
+
selector: namedBy(target),
|
|
23915
|
+
found: false
|
|
23916
|
+
};
|
|
23917
|
+
} catch (error) {
|
|
23918
|
+
return { problem: `${target} is neither an element's name nor a selector the page can read: ${error instanceof Error ? error.message.split("\n")[0] : String(error)}` };
|
|
23919
|
+
}
|
|
23920
|
+
};
|
|
23921
|
+
var framing = (view, clip) => {
|
|
23922
|
+
if (clip) return {
|
|
23740
23923
|
kind: "element",
|
|
23741
|
-
selector:
|
|
23924
|
+
selector: clip
|
|
23742
23925
|
};
|
|
23743
23926
|
return view.viewport || view.scrollTo ? { kind: "viewport" } : { kind: "page" };
|
|
23744
23927
|
};
|
|
@@ -23763,20 +23946,37 @@ var pictureOf = async (browser, url, view, origin) => {
|
|
|
23763
23946
|
if (notSignedIn) return { problem: `--as ${notSignedIn}.` };
|
|
23764
23947
|
if (!(view.fromLoad ? await page.goto(url, { waitUntil: "domcontentloaded" }).catch(() => null) : await openPage(page, url))) return { problem: `Nothing answers at ${url}.${origin ? " Start the project first: npm start" : ""}` };
|
|
23765
23948
|
const sentTo = origin ? sentElsewhere(page, new URL(url).pathname) : void 0;
|
|
23766
|
-
|
|
23767
|
-
|
|
23949
|
+
for (const target of [
|
|
23950
|
+
view.waitFor,
|
|
23951
|
+
view.scrollTo,
|
|
23952
|
+
view.clip
|
|
23953
|
+
]) {
|
|
23954
|
+
const read = target === void 0 ? void 0 : await targetOn(page, target);
|
|
23955
|
+
if (read && "problem" in read) return read;
|
|
23768
23956
|
}
|
|
23769
|
-
|
|
23770
|
-
|
|
23957
|
+
if (view.waitFor) {
|
|
23958
|
+
if (!await page.waitForSelector(awaited(view.waitFor), { timeout: 1e4 }).catch(() => null)) return { problem: `${view.waitFor} did not appear on ${url} within 10 s.` };
|
|
23959
|
+
}
|
|
23960
|
+
/** The element a target names, once it is there: what it is scrolled to, or pictured alone. */
|
|
23961
|
+
const shown = {};
|
|
23962
|
+
for (const target of [view.scrollTo, view.clip]) {
|
|
23963
|
+
if (target === void 0) continue;
|
|
23964
|
+
const read = await page.waitForSelector(awaited(target), { timeout: 1e4 }).catch(() => null) ? await targetOn(page, target) : void 0;
|
|
23965
|
+
if (!read || "problem" in read || !read.found) return { problem: `${target} is not on ${url}.` };
|
|
23966
|
+
shown[target] = read.selector;
|
|
23967
|
+
}
|
|
23968
|
+
if (view.scrollTo) await page.locator(shown[view.scrollTo]).first().scrollIntoViewIfNeeded();
|
|
23969
|
+
const how = framing(view, view.clip === void 0 ? void 0 : shown[view.clip]);
|
|
23771
23970
|
await withoutDevTools(page);
|
|
23772
23971
|
const settled = view.still ? await page.evaluate((selector) => document.querySelectorAll(selector).length, WAITING_FOR_SCROLL) : 0;
|
|
23773
|
-
const whole =
|
|
23972
|
+
const whole = how.kind === "page";
|
|
23774
23973
|
const pictures = whole ? await page.evaluate(loadImages, IMAGES_BUDGET_MS) : void 0;
|
|
23775
23974
|
if (whole) await page.evaluate(unrollPage, void 0);
|
|
23776
23975
|
if (view.still) await page.addStyleTag({ content: _ });
|
|
23777
23976
|
return {
|
|
23778
23977
|
page,
|
|
23779
|
-
|
|
23978
|
+
how,
|
|
23979
|
+
png: await capture(page, how),
|
|
23780
23980
|
scheme: await paintedScheme(page, view.scheme ?? "light"),
|
|
23781
23981
|
settled,
|
|
23782
23982
|
unloaded: pictures?.missing ?? 0,
|
|
@@ -23894,8 +24094,10 @@ var clickThrough = async (taken, how, clicks, { frames, every }) => {
|
|
|
23894
24094
|
}];
|
|
23895
24095
|
const clicked = [];
|
|
23896
24096
|
for (const target of clicks) {
|
|
23897
|
-
const
|
|
23898
|
-
if (
|
|
24097
|
+
const read = await targetOn(taken.page, target);
|
|
24098
|
+
if ("problem" in read) return read;
|
|
24099
|
+
if (!read.found) return { problem: `${target} is not on the page: --click takes an element's name, a tag or a selector.` };
|
|
24100
|
+
const element = taken.page.locator(read.selector).first();
|
|
23899
24101
|
const before = moments[moments.length - 1].png;
|
|
23900
24102
|
try {
|
|
23901
24103
|
await element.click({ timeout: 3e3 });
|
|
@@ -23959,13 +24161,19 @@ var playSteps = async (taken, how, steps) => {
|
|
|
23959
24161
|
};
|
|
23960
24162
|
for (const [index, step] of steps.entries()) try {
|
|
23961
24163
|
if (step.kind === "click" || step.kind === "type") {
|
|
23962
|
-
const
|
|
23963
|
-
if (
|
|
23964
|
-
await
|
|
23965
|
-
if (step.kind === "type")
|
|
24164
|
+
const read = await targetOn(page, step.target);
|
|
24165
|
+
if ("problem" in read || !read.found) return { problem: `Step ${String(index + 1)}: ${"problem" in read ? read.problem : `${step.target} is not on the page — its name, a tag or a selector; one with spaces in quotes: type ".panel textarea" hola`}.` };
|
|
24166
|
+
await page.locator(read.selector).first().click({ timeout: 3e3 });
|
|
24167
|
+
if (step.kind === "type") {
|
|
24168
|
+
if (!await page.evaluate(() => {
|
|
24169
|
+
const focused = document.activeElement;
|
|
24170
|
+
return focused instanceof HTMLElement && (focused.isContentEditable || focused.matches("input, textarea, select"));
|
|
24171
|
+
}, void 0)) return { problem: `Step ${String(index + 1)}: clicking ${step.target} leaves no field focused, so the text would go to the page itself — name the field: type ".panel textarea" hola` };
|
|
24172
|
+
await page.keyboard.type(step.text);
|
|
24173
|
+
}
|
|
23966
24174
|
} else if (step.kind === "press") await page.keyboard.press(step.key);
|
|
23967
24175
|
else if (step.kind === "wait") await page.waitForTimeout(step.ms);
|
|
23968
|
-
else if (step.kind === "wait-for") await page.waitForSelector(
|
|
24176
|
+
else if (step.kind === "wait-for") await page.waitForSelector(awaited(step.target), { timeout: 1e4 });
|
|
23969
24177
|
else if (step.kind === "shot") await picture(step.label ?? `step ${String(index + 1)}`);
|
|
23970
24178
|
else for (let frame = 1; frame <= step.count; frame += 1) {
|
|
23971
24179
|
if (frame > 1) await page.waitForTimeout(step.every);
|
|
@@ -24052,16 +24260,17 @@ var shot = async (route, options) => {
|
|
|
24052
24260
|
...options.clip ? { clip: options.clip } : {},
|
|
24053
24261
|
...options.scrollTo ? { scrollTo: options.scrollTo } : {},
|
|
24054
24262
|
...options.viewport ? { viewport: true } : {},
|
|
24263
|
+
...options.presence ? { presence: true } : {},
|
|
24055
24264
|
...account ? { account } : {},
|
|
24056
24265
|
...fromLoad ? { fromLoad } : {},
|
|
24057
24266
|
still: !options.clip && !options.scrollTo && !options.viewport && (options.frames ?? 0) <= 1 && clicks.length === 0
|
|
24058
24267
|
};
|
|
24059
|
-
const how = framing(view);
|
|
24060
24268
|
const taken = await pictureOf(browser, `${where.origin}${pathname}`, view, where.origin);
|
|
24061
24269
|
if ("problem" in taken) {
|
|
24062
24270
|
fail(taken.problem);
|
|
24063
24271
|
return;
|
|
24064
24272
|
}
|
|
24273
|
+
const { how } = taken;
|
|
24065
24274
|
const name = pathname === "/" ? "home" : pathname.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "");
|
|
24066
24275
|
const out = path.resolve(project.root, options.out ?? `tmp/shots/${name}-${String(view.width)}-${taken.scheme}.png`);
|
|
24067
24276
|
const base = out.replace(/\.png$/, "");
|
|
@@ -27503,14 +27712,14 @@ program.command("login").description("Sign in, in your browser. The session is k
|
|
|
27503
27712
|
program.command("logout").description("Sign out: the session is revoked on the platform and forgotten here").action(() => logout());
|
|
27504
27713
|
program.command("whoami").description("Who the CLI is signed in as, and the space it works in").option("--json", "One object: { api, user, space }, for a tool or an agent").option(...API_OPTION).action((options) => whoami(options));
|
|
27505
27714
|
spaceGroup.command("use").description("Choose the space to work in, in your browser. One at a time: it replaces the one chosen before").option(...API_OPTION).action((options) => space$2(options));
|
|
27506
|
-
pageGroup.command("check").argument("[paths...]", "The pages: /about /writers, in one browser. The home page when left out").description("Whether a page of the running project is whole, in text: every element on screen, no broken image, no console error, no failed flow").addOption(widthsOption("The widths to check it at, separated by commas", [1440, 390])).addOption(schemeOption()).option("--state", "Also what the page holds: its state, and every source by name").option("--element <id>", "Also one element: what it reads, its own state, whether it is on screen").option("--ssr", "Also the HTML the server sent against the hydrated page: what a server provider sent late").option("--click <id>", "Click one element once the page settles, and say what it changed — or that nothing did").addOption(new Option("--fill <id=value>", "Fill a field before the click, as a visitor types in it — once per field; a box takes true or false").argParser(fill)).option("--as <username>", "Sign in first as this account, through the server’s /auth routes — the password from PLITZI_CHECK_PASSWORD, in .env").option("--json", "One object per page and width, for a tool or an agent").action((paths, options) => check(paths, options));
|
|
27715
|
+
pageGroup.command("check").argument("[paths...]", "The pages: /about /writers, in one browser. The home page when left out").description("Whether a page of the running project is whole, in text: every element on screen, no broken image, no console error, no failed flow").addOption(widthsOption("The widths to check it at, separated by commas", [1440, 390])).addOption(schemeOption()).option("--state", "Also what the page holds: its state, and every source by name").option("--element <id>", "Also one element: what it reads, its own state, whether it is on screen").option("--ssr", "Also the HTML the server sent against the hydrated page: what a server provider sent late").option("--click <id>", "Click one element once the page settles, and say what it changed — or that nothing did").addOption(new Option("--fill <id=value>", "Fill a field before the click, as a visitor types in it — once per field; a box takes true or false").argParser(fill)).option("--as <username>", "Sign in first as this account, through the server’s /auth routes — the password from PLITZI_CHECK_PASSWORD, in .env").option("--presence", "Take part in the page’s realtime channels as a visitor does — arrive, announce, send. Otherwise it only watches them").option("--json", "One object per page and width, for a tool or an agent").action((paths, options) => check(paths, options));
|
|
27507
27716
|
spaceGroup.command("fix").description("What authoring would fix in the space, as edits to your source: shown as a diff; with --write written, formatted and checked").option("--write", "Write the edits — kept only when the space authors with each fix gone and no problem added").option("--json", "The plan as one object, for a tool or an agent").action((options) => fix(options));
|
|
27508
27717
|
pageGroup.command("import").argument("<url>", "The page to start from: https://example.com/pricing").description("A page of a site you verified, as a place to start writing from: its tokens, the outline of its blocks per breakpoint, its lists as JSON — never its words").option("-o, --out <dir>", "Where it is written, inside the project", "src/imported").addOption(widthsOption("The widths it is measured at: the widest is desktop, then tablet and mobile", [
|
|
27509
27718
|
1440,
|
|
27510
27719
|
768,
|
|
27511
27720
|
390
|
|
27512
27721
|
])).option("-f, --force", "Write over what --out already holds").option("--account", "A site not served from this machine: ask your Plitzi account whether one of your spaces verified its domain (signs in)").option("--json", "One object, for a tool or an agent").option(...API_OPTION).option(...DRY_RUN_OPTION).action((url, options) => importPage(url, options));
|
|
27513
|
-
pageGroup.command("shot").argument("[path]", "The page: /about. The home page when left out").description("A picture of one page of the running project — and, asked, how it differs from another or what moves").addOption(new Option("--width <px>", "The viewport width").argParser(width).default(1280)).addOption(new Option("--height <px>", "The viewport height (the picture is the whole page unless --viewport, --scroll-to or --clip)").argParser(positiveInteger).default(800)).addOption(schemeOption()).option("-o, --out <file>", "Where the picture goes. tmp/shots/<page>-<width>-<scheme>.png by default").option("--compare <url>", "Another site: the same page there, side by side, and how much differs by section").addOption(new Option("--frames <n>", "Pictures taken one after another: which sections move (a marquee, an autoplay)").argParser(positiveInteger)).addOption(new Option("--every <ms>", "How far apart --frames are taken").argParser(positiveInteger).default(500)).addOption(new Option("--from <moment>", "When --frames start: once the page settles, or as soon as its HTML is in (load) — what plays as it arrives").choices([...SHOT_MOMENTS]).default("settled")).option("--wait-for <element>", "An element to wait for first: its name (data-plitzi-el) or a CSS selector").option("--clip <element>", "Only this element — its name or a CSS selector — scrolled to wherever it is").option("--scroll-to <element>", "The page scrolled until this element is in view; the picture is the screen there").option("--viewport", "Only what fits the viewport, not the whole page").option("--click <element...>", "Click these in order once the page settles — each its name or a CSS selector, inside a plugin too — picturing what each changed (--frames pictures --every ms apart after each)").option("--sheet", "Every picture taken — before, after each click, each frame — on one contact sheet").option("--steps <script>", "An interaction, step by step: \"click <el>; type <el> <text>; press <key>; wait <ms>; wait-for <el>; shot [label]; frames <n> [ms]\" — or @file with one per line").option("--reduced-motion", "As a visitor who asked for less motion").option("--as <username>", "Sign in first as this account, through the server’s /auth routes — the password from PLITZI_CHECK_PASSWORD, in .env").option("--json", "One object, for a tool or an agent").action((path, options) => shot(path, options));
|
|
27722
|
+
pageGroup.command("shot").argument("[path]", "The page: /about. The home page when left out").description("A picture of one page of the running project — and, asked, how it differs from another or what moves").addOption(new Option("--width <px>", "The viewport width").argParser(width).default(1280)).addOption(new Option("--height <px>", "The viewport height (the picture is the whole page unless --viewport, --scroll-to or --clip)").argParser(positiveInteger).default(800)).addOption(schemeOption()).option("-o, --out <file>", "Where the picture goes. tmp/shots/<page>-<width>-<scheme>.png by default").option("--compare <url>", "Another site: the same page there, side by side, and how much differs by section").addOption(new Option("--frames <n>", "Pictures taken one after another: which sections move (a marquee, an autoplay)").argParser(positiveInteger)).addOption(new Option("--every <ms>", "How far apart --frames are taken").argParser(positiveInteger).default(500)).addOption(new Option("--from <moment>", "When --frames start: once the page settles, or as soon as its HTML is in (load) — what plays as it arrives").choices([...SHOT_MOMENTS]).default("settled")).option("--wait-for <element>", "An element to wait for first: its name (data-plitzi-el) or a CSS selector").option("--clip <element>", "Only this element — its name or a CSS selector — scrolled to wherever it is").option("--scroll-to <element>", "The page scrolled until this element is in view; the picture is the screen there").option("--viewport", "Only what fits the viewport, not the whole page").option("--click <element...>", "Click these in order once the page settles — each its name or a CSS selector, inside a plugin too — picturing what each changed (--frames pictures --every ms apart after each)").option("--sheet", "Every picture taken — before, after each click, each frame — on one contact sheet").option("--steps <script>", "An interaction, step by step: \"click <el>; type <el> <text>; press <key>; wait <ms>; wait-for <el>; shot [label]; frames <n> [ms]\" — or @file with one per line").option("--reduced-motion", "As a visitor who asked for less motion").option("--as <username>", "Sign in first as this account, through the server’s /auth routes — the password from PLITZI_CHECK_PASSWORD, in .env").option("--presence", "Take part in the page’s realtime channels as a visitor does — arrive, announce, send. Otherwise it only watches them").option("--json", "One object, for a tool or an agent").action((path, options) => shot(path, options));
|
|
27514
27723
|
program.command("verify").description("Whether the project is left passing: author, lints, types, format and every page, only the problems said").option("--no-pages", "Leave the pages out — said as such").option("--keep-going", "Run every check even after one fails — by default the first failure ends the run").option("--json", "One object, for a tool or an agent").action((options) => verify(options));
|
|
27515
27724
|
elementGroup.command("where").argument("<query>", "An element’s id, a class it wears, or words it shows: hero-cta, navLink, \"Get started\"").description("Where the project’s code writes an element: the file, the line and the call itself").addOption(new Option("--by <reading>", "Read the query one way only, not the first of id, class and words that matches").choices(WHERE_READINGS)).option("--json", "One object, for a tool or an agent").action((query, options) => where(query, options));
|
|
27516
27725
|
elementGroup.command("edit").argument("<id>", "The element, by its id: hero-cta").description("Change an element’s attributes in the call that writes it, then check the space still authors").option("--set <key=value...>", "An attribute to write: content=\"Start free\", required=true").option("--remove <key...>", "An attribute to take out").option("--every", "The call writes other elements too, and the change is for every one").option("--json", "One object, for a tool or an agent").action((id, options) => edit(id, options));
|
|
@@ -27528,6 +27737,7 @@ pluginGroup.command("upload").argument("[zip]", "The zip plitzi plugin pack buil
|
|
|
27528
27737
|
var functions = program.command("functions").description(`The space’s own server code: ${h$1}/ in this project is a working copy of it`);
|
|
27529
27738
|
functions.command("pull").description(`Write the space’s functions into ${h$1}/ — refused when that would overwrite what is not pushed`).option("-f, --force", "Overwrite what is not pushed, or a copy of another space").option(...API_OPTION).option(...DRY_RUN_OPTION).action((options) => pullFunctions(options));
|
|
27530
27739
|
functions.command("push").description(`Save ${h$1}/ as the space’s draft: built and checked on the platform, refused if it moved on since`).option(...API_OPTION).option(...DRY_RUN_OPTION).action((options) => pushFunctions(options));
|
|
27740
|
+
functions.command("add").argument("<package>", "An npm package the project installed — ical.js, @scope/name").description(`Bundle a package into ${h$1}/vendor/ for the functions to import, as a function carries its dependencies — web APIs only`).option(...DRY_RUN_OPTION).action((name, options) => addFunctionsPackage(name, options));
|
|
27531
27741
|
functions.command("try").argument("<task>", "The task, <namespace>.<action>").description("Run one task of the draft in the sandbox: its value, what it logged, and why it failed").option("--params <json>", "Its params, as a JSON object").option(...API_OPTION).action((task, options) => tryFunction(task, options));
|
|
27532
27742
|
functions.command("dev").argument("<task>", "The task, <namespace>.<action>").description(`Run one task from ${h$1}/ on this machine, as the platform runs it — nothing reaches the space`).option("--params <json>", "Its params, as a JSON object").option("-w, --watch", `Run it again every time a file of ${h$1}/ is saved`).action((task, options) => devFunction(task, options));
|
|
27533
27743
|
runtime.command("push").description("Pack this project’s runtime module and keep it as the space’s draft runtime").option("--entry <path>", "The module whose default export is defineRuntime(…)", "src/runtime/index.ts").option(...API_OPTION).option(...DRY_RUN_OPTION).action((options) => pushRuntime(options));
|