livemark 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/actions/config/define.d.ts +67 -3
- package/build/actions/config/define.js +3 -3
- package/build/actions/config/load.js +23 -2
- package/build/components/Layout.js +9 -7
- package/build/components/SidebarSections.js +7 -7
- package/build/content/article.js +3 -3
- package/build/helpers/resolve-base.d.ts +6 -0
- package/build/helpers/resolve-base.js +13 -0
- package/build/helpers/resolve-base.unit.d.ts +1 -0
- package/build/helpers/resolve-base.unit.js +49 -0
- package/build/helpers/section.d.ts +10 -2
- package/build/helpers/section.js +19 -3
- package/build/helpers/section.unit.js +32 -2
- package/build/models/config.d.ts +29 -11
- package/build/models/config.js +9 -11
- package/build/models/section.d.ts +7 -5
- package/build/models/section.js +4 -4
- package/package.json +1 -1
- package/source/actions/config/define.ts +4 -6
- package/source/actions/config/load.ts +26 -6
- package/source/components/Layout.tsx +11 -11
- package/source/components/SidebarSections.tsx +8 -5
- package/source/content/article.ts +2 -2
- package/source/helpers/resolve-base.ts +11 -0
- package/source/helpers/resolve-base.unit.ts +61 -0
- package/source/helpers/section.ts +18 -3
- package/source/helpers/section.unit.ts +43 -1
- package/source/models/config.ts +32 -14
- package/source/models/section.ts +7 -5
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it } from "vite-plus/test"
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
customSectionActive,
|
|
4
|
+
matchSection,
|
|
5
|
+
partitionBySection,
|
|
6
|
+
} from "./section.ts"
|
|
3
7
|
|
|
4
8
|
describe("matchSection", () => {
|
|
5
9
|
const sections = [
|
|
@@ -69,3 +73,41 @@ describe("partitionBySection", () => {
|
|
|
69
73
|
])
|
|
70
74
|
})
|
|
71
75
|
})
|
|
76
|
+
|
|
77
|
+
describe("customSectionActive", () => {
|
|
78
|
+
it("should not match an absolute http url", () => {
|
|
79
|
+
expect(customSectionActive("https://x.com/y", "/y/")).toBe(false)
|
|
80
|
+
expect(customSectionActive("http://x.com/y", "/y/")).toBe(false)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it("should not match a protocol-relative url", () => {
|
|
84
|
+
expect(customSectionActive("//cdn.x.com/y", "/y/")).toBe(false)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it("should not match a hash url", () => {
|
|
88
|
+
expect(customSectionActive("#section", "/section/")).toBe(false)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it("should match the exact path", () => {
|
|
92
|
+
expect(customSectionActive("/about", "/about/")).toBe(true)
|
|
93
|
+
expect(customSectionActive("/about/", "/about/")).toBe(true)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it("should match a descendant path", () => {
|
|
97
|
+
expect(customSectionActive("/about", "/about/team/")).toBe(true)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it("should not match a sibling path with shared prefix", () => {
|
|
101
|
+
expect(customSectionActive("/about", "/aboutus/")).toBe(false)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it("should match exact root only", () => {
|
|
105
|
+
expect(customSectionActive("/", "/")).toBe(true)
|
|
106
|
+
expect(customSectionActive("/", "/about/")).toBe(false)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it("should ignore query and hash on the url", () => {
|
|
110
|
+
expect(customSectionActive("/about?x=1", "/about/")).toBe(true)
|
|
111
|
+
expect(customSectionActive("/about#top", "/about/team/")).toBe(true)
|
|
112
|
+
})
|
|
113
|
+
})
|
package/source/models/config.ts
CHANGED
|
@@ -15,22 +15,33 @@ export type ViteOverride =
|
|
|
15
15
|
| ViteUserConfig
|
|
16
16
|
| ((env: ConfigEnv) => ViteUserConfig | Promise<ViteUserConfig>)
|
|
17
17
|
|
|
18
|
+
/** Sub-path mount. String form is used as-is; function form is called
|
|
19
|
+
* with Vite's `command` (`"serve"` in dev, `"build"` in production) so
|
|
20
|
+
* the user can branch (typical case: serve at `/` in dev but at
|
|
21
|
+
* `/repo/` in production for GitHub Pages). The build pipeline
|
|
22
|
+
* resolves it to a string before any runtime sees it. */
|
|
23
|
+
export type Base = string | ((command: "build" | "serve") => string | undefined)
|
|
24
|
+
|
|
18
25
|
/**
|
|
19
26
|
* User-provided configuration for Livemark.
|
|
27
|
+
*
|
|
28
|
+
* `vite` and `base` are lifted from `unknown` to their public types so
|
|
29
|
+
* `defineConfig` shows the right shape in editors. Use this type for
|
|
30
|
+
* the input to `defineConfig` — it keeps defaulted fields optional
|
|
31
|
+
* (because zod input ≠ output for fields with `.default()`).
|
|
20
32
|
*/
|
|
21
|
-
export type UserConfig = Omit<z.
|
|
33
|
+
export type UserConfig = Omit<z.input<typeof UserConfig>, "vite" | "base"> & {
|
|
22
34
|
vite?: ViteOverride
|
|
35
|
+
base?: Base
|
|
23
36
|
}
|
|
24
37
|
export const UserConfig = z.object({
|
|
25
38
|
site: z.string().optional(),
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return trimmed ? `/${trimmed}` : undefined
|
|
33
|
-
}),
|
|
39
|
+
// Stored as `unknown` in the schema (zod can't type a function and
|
|
40
|
+
// string union meaningfully); the public TypeScript surface above
|
|
41
|
+
// lifts it back to `Base` for editor support. The build pipeline
|
|
42
|
+
// resolves it via `resolveBase()` before any runtime consumer sees
|
|
43
|
+
// it, so the runtime `WebsiteConfig.base` is strictly `string`.
|
|
44
|
+
base: z.unknown().optional(),
|
|
34
45
|
favicon: z.string().optional(),
|
|
35
46
|
logo: z.string().optional(),
|
|
36
47
|
title: z.string().default("Livemark"),
|
|
@@ -48,17 +59,20 @@ export const UserConfig = z.object({
|
|
|
48
59
|
vite: z.unknown().optional(),
|
|
49
60
|
})
|
|
50
61
|
|
|
51
|
-
/** Website configuration injected at build time via Vite define
|
|
62
|
+
/** Website configuration injected at build time via Vite define.
|
|
63
|
+
* `base` is strictly a string here — the build pipeline has already
|
|
64
|
+
* resolved any function form via `resolveBase()`. */
|
|
52
65
|
export type WebsiteConfig = z.infer<typeof WebsiteConfig>
|
|
53
66
|
export const WebsiteConfig = UserConfig.pick({
|
|
54
67
|
title: true,
|
|
55
68
|
description: true,
|
|
56
69
|
site: true,
|
|
57
|
-
base: true,
|
|
58
70
|
favicon: true,
|
|
59
71
|
logo: true,
|
|
60
72
|
links: true,
|
|
61
73
|
sections: true,
|
|
74
|
+
}).extend({
|
|
75
|
+
base: z.string().optional(),
|
|
62
76
|
})
|
|
63
77
|
|
|
64
78
|
/**
|
|
@@ -73,9 +87,13 @@ export const SystemConfig = z.object({
|
|
|
73
87
|
/**
|
|
74
88
|
* Fully resolved Livemark configuration.
|
|
75
89
|
*
|
|
76
|
-
* `vite` stays `unknown`
|
|
90
|
+
* `vite` stays `unknown` because that's what the runtime schema
|
|
77
91
|
* produces — consumer-facing typing happens via {@link UserConfig} so
|
|
78
|
-
* `defineConfig` shows the right shape in editors.
|
|
92
|
+
* `defineConfig` shows the right shape in editors. `base` is lifted to
|
|
93
|
+
* `string | undefined` because `loadConfig()` resolves any function
|
|
94
|
+
* form via `resolveBase()` before returning.
|
|
79
95
|
*/
|
|
80
|
-
export type Config = z.infer<typeof Config>
|
|
96
|
+
export type Config = Omit<z.infer<typeof Config>, "base"> & {
|
|
97
|
+
base?: string
|
|
98
|
+
}
|
|
81
99
|
export const Config = UserConfig.merge(SystemConfig)
|
package/source/models/section.ts
CHANGED
|
@@ -29,10 +29,12 @@ export const ChangelogSection = BaseSection.extend({
|
|
|
29
29
|
version: z.boolean().optional(),
|
|
30
30
|
})
|
|
31
31
|
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
/** Custom section: renders as a link to an arbitrary URL — absolute
|
|
33
|
+
* (`https://…`) or internal (`/changelog`). Internal URLs participate
|
|
34
|
+
* in active-state highlighting like routed sections. */
|
|
35
|
+
export type CustomSection = z.infer<typeof CustomSection>
|
|
36
|
+
export const CustomSection = BaseSection.extend({
|
|
37
|
+
type: z.literal("custom"),
|
|
36
38
|
url: z.string(),
|
|
37
39
|
})
|
|
38
40
|
|
|
@@ -54,6 +56,6 @@ export const Section = z.preprocess(
|
|
|
54
56
|
ArticleSection,
|
|
55
57
|
BlogSection,
|
|
56
58
|
ChangelogSection,
|
|
57
|
-
|
|
59
|
+
CustomSection,
|
|
58
60
|
]),
|
|
59
61
|
)
|