@mapled/cli 0.14.1 → 0.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -256,7 +256,7 @@ npx @mapled/cli preview
256
256
  npx @mapled/cli preview articles hello-world
257
257
  ```
258
258
 
259
- Prints a Preview link — the one the **Preview** button in Mapled opens: the site in draft mode, with every saved change that isn't published yet. Name a collection and a record's slug (or id) and the link lands on the record's page, the one the pushed site manifest says shows it; a collection alone opens the page that lists it, a single its page, nothing at all the home page. Mapled makes the link after checking that the site answers and mounts its preview route; it works once, for five minutes. `--open` opens it in your browser instead of printing it; `--json` prints the link with the page and when it expires.
259
+ Prints a Preview link — the one the **Preview** button in Mapled opens: the site in draft mode, with every saved change that isn't published yet. Name a collection and a record's slug (or id) and the link lands on the record's page, the one the pushed site manifest says shows it; a collection alone opens the page that lists it, a single its page, nothing at all the home page. Mapled makes the link after checking that the site answers and mounts its preview route; it works once, for five minutes. A plain HTML site whose pages are built with the content in them has no page for a record it wasn't built with: for such a record the command says so instead of printing a link — its page appears once the site is built with it. `--open` opens it in your browser instead of printing it; `--json` prints the link with the page and when it expires.
260
260
 
261
261
  ## Options
262
262
 
package/dist/commands.js CHANGED
@@ -507,6 +507,11 @@ export async function preview(ctx, flags, words) {
507
507
  if (answer.status === "not_set_up") {
508
508
  throw new CliError(`${clean(answer.origin)} has no preview route — mount createPreviewHandler from "@mapled/next/server" at /api/mapled/preview and redeploy.`);
509
509
  }
510
+ if (answer.status === "no_route") {
511
+ // a site with its content baked in at build time has no page for a record it wasn't built with (§22.7 п. 3)
512
+ const where = answer.path ? `at ${clean(answer.path, 500)}` : "for this record";
513
+ throw new CliError(`${clean(answer.origin)} has no page ${where} — if the record is new, its page appears once the site is built with it. Then try again.`);
514
+ }
510
515
  // the link is printed as it came (masking would drop the token): printable ASCII only
511
516
  if (typeof answer.url !== "string" || !/^https?:\/\/[!-~]+$/.test(answer.url)) {
512
517
  throw new CliError("Mapled answered with a link this CLI can't print. Update @mapled/cli and try again.");
package/dist/html5.d.ts CHANGED
@@ -18,11 +18,21 @@ import { type Token, type TreeAdapter, type TreeAdapterTypeMap } from "parse5";
18
18
  before a <table>: indexOf), the adoption agency (a misnested </b>:
19
19
  splice from the front) and repeated <html>/<body> tags (every
20
20
  attribute so far) walk them — 160,000 "a<br>" in a table: 11 s.
21
- The worst page within the cap is the depth times its start tags. */
21
+ The worst page within the cap is the depth times its start tags.
22
+
23
+ parse5 can't read a numeric character reference of 309 or more decimal
24
+ digits, or of 256 or more hex ones, at all: BadReference. */
22
25
  /** How deep elements may be open at once — Chrome's own limit of the tree it builds. */
23
26
  export declare const MAX_OPEN = 512;
24
27
  export declare class TooDeep extends Error {
25
28
  }
29
+ /** A numeric character reference parse5 can't read: its decoder (entities)
30
+ multiplies by 10 or 16 to the power of the digits — Infinity past 308
31
+ decimal or 255 hex ones — and 0 × Infinity is NaN, on which parse5
32
+ throws RangeError. Browsers read it as a character. The same guard is
33
+ in the preview proxy's reader (apps/api/src/lib/previewProxyHtml.ts). */
34
+ export declare class BadReference extends Error {
35
+ }
26
36
  export type Html5Attr = Token.Attribute;
27
37
  /** A node of the tree: an element (tagName), text, a comment, a doctype,
28
38
  the document or a template's content — children linked both ways. Its
@@ -61,6 +71,7 @@ type Map_ = TreeAdapterTypeMap<Html5Node, Html5Node, Html5Node, Html5Node, Html5
61
71
  /** parse5's default tree adapter, method for method, on linked children. */
62
72
  export declare const linked: TreeAdapter<Map_>;
63
73
  /** The document, with scripting on — as the runtime sees it (a <noscript>
64
- is text). Throws TooDeep past MAX_OPEN open elements. */
74
+ is text). Throws TooDeep past MAX_OPEN open elements, BadReference at a
75
+ numeric character reference parse5 can't read. */
65
76
  export declare function parseDocument(text: string): Html5Node;
66
77
  export {};
package/dist/html5.js CHANGED
@@ -7853,6 +7853,9 @@ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
7853
7853
  var MAX_OPEN = 512;
7854
7854
  var TooDeep = class extends Error {
7855
7855
  };
7856
+ var BadReference = class extends Error {
7857
+ };
7858
+ var isCodePoint = (cp) => Number.isInteger(cp) && cp >= 0 && cp <= 1114111;
7856
7859
  var Html5Node = class {
7857
7860
  constructor(nodeName, extra = {}) {
7858
7861
  this.nodeName = nodeName;
@@ -7991,6 +7994,11 @@ var Guarded = class extends Parser {
7991
7994
  names.add(this.currentAttr.name);
7992
7995
  tag.attrs.push(this.currentAttr);
7993
7996
  };
7997
+ const reference = tokenizer._flushCodePointConsumedAsCharacterReference;
7998
+ tokenizer._flushCodePointConsumedAsCharacterReference = function(cp) {
7999
+ if (!isCodePoint(cp)) throw new BadReference();
8000
+ reference.call(this, cp);
8001
+ };
7994
8002
  }
7995
8003
  onItemPush(...args) {
7996
8004
  if (this.openElements.stackTop >= MAX_OPEN) throw new TooDeep();
@@ -8001,6 +8009,7 @@ function parseDocument(text) {
8001
8009
  return Guarded.parse(text, { scriptingEnabled: true, treeAdapter: linked });
8002
8010
  }
8003
8011
  export {
8012
+ BadReference,
8004
8013
  Html5Node,
8005
8014
  MAX_OPEN,
8006
8015
  TooDeep,
package/dist/report.d.ts CHANGED
@@ -122,6 +122,10 @@ export type PreviewAnswer = {
122
122
  status: "not_set_up";
123
123
  origin: string;
124
124
  path: string | null;
125
+ } | {
126
+ status: "no_route";
127
+ origin: string;
128
+ path: string | null;
125
129
  };
126
130
  /** "5 minutes" until the link stops working, or null when unknown. */
127
131
  export declare function linkLifetime(expiresAt: string | undefined, now?: number): string | null;
@@ -20,7 +20,8 @@ export type HtmlElement = {
20
20
  };
21
21
  /** The elements of a page and their attributes — parse5's tree (html5.ts),
22
22
  a <template>'s children being its content. Built without recursion:
23
- a page nests up to MAX_OPEN elements, deeper throws TooDeep. */
23
+ a page nests up to MAX_OPEN elements, deeper throws TooDeep; a
24
+ numeric character reference parse5 can't read throws BadReference. */
24
25
  export declare function parseHtml(text: string): HtmlElement;
25
26
  /** Where a file is served and the key its bindings start with:
26
27
  index.html → "/" (index), blog/index.html → "/blog/" (blog/index),
package/dist/scanHtml.js CHANGED
@@ -1,13 +1,14 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { readdir, readFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
- import { MAX_OPEN, parseDocument, TooDeep } from "./html5.js";
4
+ import { BadReference, MAX_OPEN, parseDocument, TooDeep } from "./html5.js";
5
5
  import { targetFor } from "./manifest.js";
6
6
  const HTML_NS = "http://www.w3.org/1999/xhtml";
7
7
  const MAX_DEPTH = MAX_OPEN;
8
8
  /** The elements of a page and their attributes — parse5's tree (html5.ts),
9
9
  a <template>'s children being its content. Built without recursion:
10
- a page nests up to MAX_OPEN elements, deeper throws TooDeep. */
10
+ a page nests up to MAX_OPEN elements, deeper throws TooDeep; a
11
+ numeric character reference parse5 can't read throws BadReference. */
11
12
  export function parseHtml(text) {
12
13
  const root = { name: "#document", attrs: new Map(), children: [] };
13
14
  const pending = [[parseDocument(text), root]];
@@ -148,6 +149,7 @@ export async function scanHtml(dir, opts) {
148
149
  const noTemplate = [];
149
150
  const unusableRoutes = [];
150
151
  const tooDeep = [];
152
+ const badReferences = [];
151
153
  const notGroups = [];
152
154
  const seenRoutes = new Set();
153
155
  const pageKeys = new Set();
@@ -170,9 +172,12 @@ export async function scanHtml(dir, opts) {
170
172
  doc = parseHtml(text);
171
173
  }
172
174
  catch (e) {
173
- if (!(e instanceof TooDeep))
175
+ if (e instanceof TooDeep)
176
+ tooDeep.push(file);
177
+ else if (e instanceof BadReference)
178
+ badReferences.push(file);
179
+ else
174
180
  throw e;
175
- tooDeep.push(file);
176
181
  continue;
177
182
  }
178
183
  seenRoutes.add(served);
@@ -422,6 +427,8 @@ export async function scanHtml(dir, opts) {
422
427
  notes.push(`A list or an each without a <template> isn't filled: ${list(noTemplate)}.`);
423
428
  if (tooDeep.length > 0)
424
429
  notes.push(`Elements nest deeper than ${MAX_OPEN} levels, so the scan didn't read ${count(tooDeep) === 1 ? "this page" : "these pages"}: ${list(tooDeep)}.`);
430
+ if (badReferences.length > 0)
431
+ notes.push(`A numeric character reference (&#…;) is too long to read, so the scan didn't read ${count(badReferences) === 1 ? "this page" : "these pages"}: ${list(badReferences)}.`);
425
432
  if (unusableRoutes.length > 0)
426
433
  notes.push(`Preview can't open ${count(unusableRoutes) === 1 ? "this address" : "these addresses"} — rename the file or the slug parameter: ${list(unusableRoutes)}.`);
427
434
  // keys within the manifest's 120 characters, and still one per binding
package/dist/types.js CHANGED
@@ -153,7 +153,9 @@ function renderedField(field, owner, names, extras) {
153
153
  if (field.type === "computed" && field.computed) {
154
154
  return { required: false, rendered: computedType(field.computed.resultType) };
155
155
  }
156
- return { required: field.required, rendered: scalarType(field.type, field.options) };
156
+ const scalar = scalarType(field.type, field.options);
157
+ // translated (§28.2): one language per read — `locale` on the read picks it
158
+ return { required: field.required, rendered: field.localized === true ? { ...scalar, note: `${scalar.note}, translated` } : scalar };
157
159
  }
158
160
  /** Unique type names: the singular PascalCase of the key; the raw
159
161
  PascalCase when two keys meet there; a numeric suffix as a last resort. */
@@ -8,4 +8,7 @@
8
8
  export const VANILLA_DIGESTS = {
9
9
  "0.1.0": "sha384-mbuMcQAueviAbkTzgvxc8oDtspuYH6lFLUgE+gocGexnI8ehgSgdjnNMNL7JPk4q",
10
10
  "0.1.1": "sha384-2vgQ4g9re/eiYxEa/H3WKpWI5C9L4wCB/62c8Kq+LOfZDzmqc2ozqMGC8mZoOUqk",
11
+ "0.1.2": "sha384-bhIJoFuEGouAZtHbYeNZeN0m6fqFVWpQw+YkSMJhfk/7m5bUwS/qVWZ3xczw/1du",
12
+ "0.2.0": "sha384-HJ5XG9AhAlbKe6jPRVaef3whiVup/5WhprMwqC6RwWhpq6Pb0OsRLzbLmLJ8WH0f",
13
+ "0.2.1": "sha384-6apTHYxXrozzwFCqNU+70Z9pa/FDnhArNomcKQNWbeKRX4scjFiOc9d7wWKCOvTU",
11
14
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapled/cli",
3
- "version": "0.14.1",
3
+ "version": "0.14.2",
4
4
  "description": "Mapled CLI — sign in, link a project, generate TypeScript types for its content, create forms, preview drafts and check the site's integration.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://mapled.io",