Refactor routing in App component to enhance navigation and improve error handling by integrating dynamic routes and updating the NotFound route.

This commit is contained in:
becarta
2025-05-23 12:43:00 +02:00
parent f40db0f5c9
commit a544759a3b
11127 changed files with 1647032 additions and 0 deletions

View File

@@ -0,0 +1,300 @@
/**
* @import {
* Code,
* Construct,
* Event,
* Point,
* Resolver,
* State,
* TokenizeContext,
* Tokenizer,
* Token
* } from 'micromark-util-types'
*/
import {ok as assert} from 'devlop'
import {push, splice} from 'micromark-util-chunked'
import {classifyCharacter} from 'micromark-util-classify-character'
import {resolveAll} from 'micromark-util-resolve-all'
import {codes, constants, types} from 'micromark-util-symbol'
/** @type {Construct} */
export const attention = {
name: 'attention',
resolveAll: resolveAllAttention,
tokenize: tokenizeAttention
}
/**
* Take all events and resolve attention to emphasis or strong.
*
* @type {Resolver}
*/
// eslint-disable-next-line complexity
function resolveAllAttention(events, context) {
let index = -1
/** @type {number} */
let open
/** @type {Token} */
let group
/** @type {Token} */
let text
/** @type {Token} */
let openingSequence
/** @type {Token} */
let closingSequence
/** @type {number} */
let use
/** @type {Array<Event>} */
let nextEvents
/** @type {number} */
let offset
// Walk through all events.
//
// Note: performance of this is fine on an mb of normal markdown, but its
// a bottleneck for malicious stuff.
while (++index < events.length) {
// Find a token that can close.
if (
events[index][0] === 'enter' &&
events[index][1].type === 'attentionSequence' &&
events[index][1]._close
) {
open = index
// Now walk back to find an opener.
while (open--) {
// Find a token that can open the closer.
if (
events[open][0] === 'exit' &&
events[open][1].type === 'attentionSequence' &&
events[open][1]._open &&
// If the markers are the same:
context.sliceSerialize(events[open][1]).charCodeAt(0) ===
context.sliceSerialize(events[index][1]).charCodeAt(0)
) {
// If the opening can close or the closing can open,
// and the close size *is not* a multiple of three,
// but the sum of the opening and closing size *is* multiple of three,
// then dont match.
if (
(events[open][1]._close || events[index][1]._open) &&
(events[index][1].end.offset - events[index][1].start.offset) % 3 &&
!(
(events[open][1].end.offset -
events[open][1].start.offset +
events[index][1].end.offset -
events[index][1].start.offset) %
3
)
) {
continue
}
// Number of markers to use from the sequence.
use =
events[open][1].end.offset - events[open][1].start.offset > 1 &&
events[index][1].end.offset - events[index][1].start.offset > 1
? 2
: 1
const start = {...events[open][1].end}
const end = {...events[index][1].start}
movePoint(start, -use)
movePoint(end, use)
openingSequence = {
type: use > 1 ? types.strongSequence : types.emphasisSequence,
start,
end: {...events[open][1].end}
}
closingSequence = {
type: use > 1 ? types.strongSequence : types.emphasisSequence,
start: {...events[index][1].start},
end
}
text = {
type: use > 1 ? types.strongText : types.emphasisText,
start: {...events[open][1].end},
end: {...events[index][1].start}
}
group = {
type: use > 1 ? types.strong : types.emphasis,
start: {...openingSequence.start},
end: {...closingSequence.end}
}
events[open][1].end = {...openingSequence.start}
events[index][1].start = {...closingSequence.end}
nextEvents = []
// If there are more markers in the opening, add them before.
if (events[open][1].end.offset - events[open][1].start.offset) {
nextEvents = push(nextEvents, [
['enter', events[open][1], context],
['exit', events[open][1], context]
])
}
// Opening.
nextEvents = push(nextEvents, [
['enter', group, context],
['enter', openingSequence, context],
['exit', openingSequence, context],
['enter', text, context]
])
// Always populated by defaults.
assert(
context.parser.constructs.insideSpan.null,
'expected `insideSpan` to be populated'
)
// Between.
nextEvents = push(
nextEvents,
resolveAll(
context.parser.constructs.insideSpan.null,
events.slice(open + 1, index),
context
)
)
// Closing.
nextEvents = push(nextEvents, [
['exit', text, context],
['enter', closingSequence, context],
['exit', closingSequence, context],
['exit', group, context]
])
// If there are more markers in the closing, add them after.
if (events[index][1].end.offset - events[index][1].start.offset) {
offset = 2
nextEvents = push(nextEvents, [
['enter', events[index][1], context],
['exit', events[index][1], context]
])
} else {
offset = 0
}
splice(events, open - 1, index - open + 3, nextEvents)
index = open + nextEvents.length - offset - 2
break
}
}
}
}
// Remove remaining sequences.
index = -1
while (++index < events.length) {
if (events[index][1].type === 'attentionSequence') {
events[index][1].type = 'data'
}
}
return events
}
/**
* @this {TokenizeContext}
* Context.
* @type {Tokenizer}
*/
function tokenizeAttention(effects, ok) {
const attentionMarkers = this.parser.constructs.attentionMarkers.null
const previous = this.previous
const before = classifyCharacter(previous)
/** @type {NonNullable<Code>} */
let marker
return start
/**
* Before a sequence.
*
* ```markdown
* > | **
* ^
* ```
*
* @type {State}
*/
function start(code) {
assert(
code === codes.asterisk || code === codes.underscore,
'expected asterisk or underscore'
)
marker = code
effects.enter('attentionSequence')
return inside(code)
}
/**
* In a sequence.
*
* ```markdown
* > | **
* ^^
* ```
*
* @type {State}
*/
function inside(code) {
if (code === marker) {
effects.consume(code)
return inside
}
const token = effects.exit('attentionSequence')
// To do: next major: move this to resolver, just like `markdown-rs`.
const after = classifyCharacter(code)
// Always populated by defaults.
assert(attentionMarkers, 'expected `attentionMarkers` to be populated')
const open =
!after ||
(after === constants.characterGroupPunctuation && before) ||
attentionMarkers.includes(code)
const close =
!before ||
(before === constants.characterGroupPunctuation && after) ||
attentionMarkers.includes(previous)
token._open = Boolean(
marker === codes.asterisk ? open : open && (before || !close)
)
token._close = Boolean(
marker === codes.asterisk ? close : close && (after || !open)
)
return ok(code)
}
}
/**
* Move a point a bit.
*
* Note: `move` only works inside lines! Its not possible to move past other
* chunks (replacement characters, tabs, or line endings).
*
* @param {Point} point
* Point.
* @param {number} offset
* Amount to move.
* @returns {undefined}
* Nothing.
*/
function movePoint(point, offset) {
point.column += offset
point.offset += offset
point._bufferIndex += offset
}