@abide/abide 0.110.1 → 0.110.3

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @abide/abide
2
2
 
3
+ ## 0.110.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 804b901: the root below a mount is the bare mount, url('/') writing /docs and /docs/ redirected to it ([`9c5d3c3`](https://github.com/briancray/abide/commit/9c5d3c360c27f2d9918fb663d7aff83b22078707))
8
+
9
+ ## 0.110.2
10
+
11
+ ### Patch Changes
12
+
13
+ - 14ee265: an SVG element spelled in camelCase hydrates, the compiler asking for the tag the parser writes inside an <svg> ([`f10c81b`](https://github.com/briancray/abide/commit/f10c81bff3ce0e43762a71e24634a218312c0d93))
14
+
3
15
  ## 0.110.1
4
16
 
5
17
  ### Patch Changes
package/docs/RULEBOOK.md CHANGED
@@ -1236,8 +1236,9 @@ be refused at construction, naming its `Args` member, and the build MUST refuse
1236
1236
  19.16 `route.url` MUST hold the address a page is served at, the path `APP_URL` names included, on
1237
1237
  the server as in the browser.
1238
1238
 
1239
- 19.17 A request for the path `APP_URL` names, without its trailing `/`, MUST be redirected 308 to
1240
- that path with one, by path alone.
1239
+ 19.17 The root of an app served below the path `APP_URL` names MUST be that path without a trailing
1240
+ `/`, as `url('/')` writes it, and a request for the path with one MUST be redirected 308 to it, by
1241
+ path alone.
1241
1242
 
1242
1243
  19.18 A `Schema` derived per 19.9 MUST refuse a member its type does not declare, wherever the type
1243
1244
  carries no index signature.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abide/abide",
3
- "version": "0.110.1",
3
+ "version": "0.110.3",
4
4
  "type": "module",
5
5
  "description": "Isomorphic type-safe framework for reactive async interfaces for humans and machines",
6
6
  "license": "MIT",
@@ -81,7 +81,8 @@ export type PlacedNode = {
81
81
  */
82
82
  parent: string
83
83
  /**
84
- * An element's FOLDED tag, for the kind check `elementHere` makes. '' for the other two kinds.
84
+ * An element's tag as the parser writes it, for the kind check `elementHere` makes: folded,
85
+ * then given back SVG's camelCase (`SVG_CASE`). '' for the other two kinds.
85
86
  */
86
87
  tag: string
87
88
  /**
@@ -115,6 +116,51 @@ export type PlacedNode = {
115
116
  children: PlacedNode[]
116
117
  }
117
118
 
119
+ // THE NAMES THE PARSER GIVES BACK SVG'S CASE, folded to the case it writes — the HTML standard's
120
+ // adjustment table for foreign content. None is an HTML element, so one stands under an `<svg>`
121
+ // even where the compiler cannot see it: a component's root does not know where it is invoked.
122
+ const SVG_CASE = new Map<string, string>()
123
+ for (const name of [
124
+ 'altGlyph',
125
+ 'altGlyphDef',
126
+ 'altGlyphItem',
127
+ 'animateColor',
128
+ 'animateMotion',
129
+ 'animateTransform',
130
+ 'clipPath',
131
+ 'feBlend',
132
+ 'feColorMatrix',
133
+ 'feComponentTransfer',
134
+ 'feComposite',
135
+ 'feConvolveMatrix',
136
+ 'feDiffuseLighting',
137
+ 'feDisplacementMap',
138
+ 'feDistantLight',
139
+ 'feDropShadow',
140
+ 'feFlood',
141
+ 'feFuncA',
142
+ 'feFuncB',
143
+ 'feFuncG',
144
+ 'feFuncR',
145
+ 'feGaussianBlur',
146
+ 'feImage',
147
+ 'feMerge',
148
+ 'feMergeNode',
149
+ 'feMorphology',
150
+ 'feOffset',
151
+ 'fePointLight',
152
+ 'feSpecularLighting',
153
+ 'feSpotLight',
154
+ 'feTile',
155
+ 'feTurbulence',
156
+ 'foreignObject',
157
+ 'glyphRef',
158
+ 'linearGradient',
159
+ 'radialGradient',
160
+ 'textPath',
161
+ ])
162
+ SVG_CASE.set(name.toLowerCase(), name)
163
+
118
164
  /** A run of siblings being walked: the region's own root, or the inside of one element. */
119
165
  type Frame = {
120
166
  /**
@@ -202,7 +248,13 @@ export class Cursor {
202
248
  * emitted between its open and close tags and nowhere else. A void element is left at once.
203
249
  */
204
250
  element(node: ElementNode): PlacedNode {
205
- const at = this.record('element', node, node.lowerTag, false, [])
251
+ const at = this.record(
252
+ 'element',
253
+ node,
254
+ SVG_CASE.get(node.lowerTag) ?? node.lowerTag,
255
+ false,
256
+ [],
257
+ )
206
258
  this.frames.push({
207
259
  parent: at.name,
208
260
  within: at,
@@ -507,14 +507,14 @@ function stamp(answered: Response): Response {
507
507
 
508
508
  /**
509
509
  * The request with the mount taken off its address, where it is under the mount — or the redirect
510
- * to the mount's root, where it asked for the mount with no `/` after it.
510
+ * to the mount's root, where it asked for the mount with a `/` after it.
511
511
  *
512
512
  * 16.10 — A REQUEST UNDER THE MOUNT IS ANSWERED AS THE ADDRESS BELOW IT; one that is not — a proxy
513
513
  * that already took the prefix off — is answered as it came.
514
514
  *
515
- * THE MOUNT'S ROOT IS `/docs/`, as `url('/')` writes it. A document answered at `/docs` resolves a
516
- * relative address against `/`, which is outside the app, so the bare mount is sent to the root a
517
- * relative address resolves under.
515
+ * 19.17 — THE MOUNT'S ROOT IS `/docs`, as `url('/')` writes it, and `/docs/` is sent there so the
516
+ * root has one address. Every address abide writes is absolute under the mount, so none resolves
517
+ * against the page's.
518
518
  */
519
519
  function belowMount(request: Request): Request | Response {
520
520
  const mount = MOUNT.current()
@@ -522,10 +522,10 @@ function belowMount(request: Request): Request | Response {
522
522
  const url = new URL(request.url)
523
523
  // A PATH RATHER THAN A URL: the origin this request names is the one it reached, which behind
524
524
  // a proxy is not the one the browser asked.
525
- if (url.pathname === mount)
525
+ if (url.pathname === `${mount}/`)
526
526
  return new Response(null, {
527
527
  status: 308,
528
- headers: { location: `${mount}/${url.search}` },
528
+ headers: { location: `${mount}${url.search}` },
529
529
  })
530
530
  const below = unmounted(url.pathname)
531
531
  if (below === undefined || below === url.pathname) return request
@@ -25,10 +25,14 @@ function documentMount(): string {
25
25
  return documentMountRead
26
26
  }
27
27
 
28
- /** An address below the app's root, as the address it is served at. */
28
+ /**
29
+ * An address below the app's root, as the address it is served at. 19.17 — the root below a mount
30
+ * is the bare mount, `/docs` rather than `/docs/`.
31
+ */
29
32
  export function mounted(address: string): string {
30
33
  const mount = MOUNT.current()
31
- return mount === '' ? address : `${mount}${address}`
34
+ if (mount === '') return address
35
+ return address === '/' ? mount : `${mount}${address}`
32
36
  }
33
37
 
34
38
  /**