@rimelight/config 0.0.4 → 0.0.6
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 +86 -3
- package/astro/index.js +329 -0
- package/astro/index.ts +415 -0
- package/package.json +48 -4
- package/tsconfig/{solid.json → astro-solid.json} +3 -3
- package/tsconfig/astro.json +12 -0
- package/tsconfig/base.json +20 -18
- package/vite-plus/base.js +122 -2
- package/vite-plus/base.ts +139 -5
package/README.md
CHANGED
|
@@ -20,19 +20,32 @@ Default strict TypeScript configuration for all Rimelight projects:
|
|
|
20
20
|
}
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
###
|
|
23
|
+
### Astro Config
|
|
24
24
|
|
|
25
|
-
For
|
|
25
|
+
For pure Astro projects:
|
|
26
26
|
|
|
27
27
|
```json
|
|
28
28
|
{
|
|
29
|
-
"extends": "@rimelight/config/tsconfig/
|
|
29
|
+
"extends": "@rimelight/config/tsconfig/astro.json"
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Astro + SolidJS Config
|
|
34
|
+
|
|
35
|
+
For Astro projects using SolidJS components:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"extends": "@rimelight/config/tsconfig/astro-solid.json"
|
|
30
40
|
}
|
|
31
41
|
```
|
|
32
42
|
|
|
33
43
|
## Vite+ Configs
|
|
34
44
|
|
|
45
|
+
### App / Standard Config
|
|
46
|
+
|
|
35
47
|
```typescript
|
|
48
|
+
import { defineConfig } from "vite-plus"
|
|
36
49
|
import { rimelightConfig } from "@rimelight/config/vite-plus/base"
|
|
37
50
|
|
|
38
51
|
export default defineConfig({
|
|
@@ -41,6 +54,76 @@ export default defineConfig({
|
|
|
41
54
|
})
|
|
42
55
|
```
|
|
43
56
|
|
|
57
|
+
### Package Config (with Auto-Entry Discovery)
|
|
58
|
+
|
|
59
|
+
For library / workspace packages:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { defineConfig } from "vite-plus"
|
|
63
|
+
import { rimelightPackConfig } from "@rimelight/config/vite-plus/base"
|
|
64
|
+
|
|
65
|
+
export default defineConfig(
|
|
66
|
+
rimelightPackConfig({
|
|
67
|
+
// Automatically discovers all entry modules in src/ (ignoring tests and .d.ts)
|
|
68
|
+
autoEntry: true
|
|
69
|
+
})
|
|
70
|
+
)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Astro Configs
|
|
74
|
+
|
|
75
|
+
### Full Standard Rimelight Site Config
|
|
76
|
+
|
|
77
|
+
Zero-boilerplate setup with preconfigured Cloudflare adapter, Cloudflare cache, SWR route rules, Fontsource fonts (Noto Sans, Noto Serif, JetBrains Mono), responsive image defaults, and declarative package flags:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { defineConfig } from "astro/config"
|
|
81
|
+
import { rimelightAstroConfig } from "@rimelight/config/astro"
|
|
82
|
+
import en from "./src/translations/en.json"
|
|
83
|
+
import pt from "./src/translations/pt.json"
|
|
84
|
+
|
|
85
|
+
export default defineConfig(
|
|
86
|
+
rimelightAstroConfig({
|
|
87
|
+
// Automatically derives site: "https://example.com"
|
|
88
|
+
// and image.domains: ["example.com", "cdn.example.com", "cdn.rimelight.com"]
|
|
89
|
+
domain: "example.com",
|
|
90
|
+
|
|
91
|
+
// Declarative package flags (dynamically imported, tree-shakeable)
|
|
92
|
+
solid: true,
|
|
93
|
+
cms: true,
|
|
94
|
+
security: true,
|
|
95
|
+
i18n: {
|
|
96
|
+
translations: { en, pt }
|
|
97
|
+
},
|
|
98
|
+
ui: {
|
|
99
|
+
logos: { ... }
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Granular / Composable Presets
|
|
106
|
+
|
|
107
|
+
If you prefer to compose configuration piecemeal:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { defineConfig } from "astro/config"
|
|
111
|
+
import {
|
|
112
|
+
cloudflarePreset,
|
|
113
|
+
cacheRulesPreset,
|
|
114
|
+
fontsPreset,
|
|
115
|
+
imagePreset
|
|
116
|
+
} from "@rimelight/config/astro"
|
|
117
|
+
|
|
118
|
+
export default defineConfig({
|
|
119
|
+
site: "https://example.com",
|
|
120
|
+
...cloudflarePreset(),
|
|
121
|
+
...cacheRulesPreset(),
|
|
122
|
+
...fontsPreset(),
|
|
123
|
+
...imagePreset({ domains: ["example.com"] })
|
|
124
|
+
})
|
|
125
|
+
```
|
|
126
|
+
|
|
44
127
|
## Config Details
|
|
45
128
|
|
|
46
129
|
### TypeScript Base Config
|
package/astro/index.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import fs from "node:fs"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import cloudflare from "@astrojs/cloudflare"
|
|
4
|
+
import { cacheCloudflare } from "@astrojs/cloudflare/cache"
|
|
5
|
+
import { fontProviders } from "astro/config"
|
|
6
|
+
|
|
7
|
+
export function cacheRulesPreset(options = {}) {
|
|
8
|
+
const { apiSwrSeconds = 600, pageMaxAgeSeconds = 300, customRules = {} } = options
|
|
9
|
+
return {
|
|
10
|
+
routeRules: {
|
|
11
|
+
"/api/[...path]": {
|
|
12
|
+
swr: apiSwrSeconds
|
|
13
|
+
},
|
|
14
|
+
"/[...path]": {
|
|
15
|
+
maxAge: pageMaxAgeSeconds
|
|
16
|
+
},
|
|
17
|
+
...customRules
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function fontsPreset(options = {}) {
|
|
23
|
+
const defaultFonts = [
|
|
24
|
+
{
|
|
25
|
+
name: "Noto Sans",
|
|
26
|
+
cssVariable: "--font-sans",
|
|
27
|
+
fallbacks: ["sans-serif"],
|
|
28
|
+
subsets: ["latin", "latin-ext"],
|
|
29
|
+
weights: [400, 500, 600, 700],
|
|
30
|
+
styles: ["normal"]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "Noto Serif",
|
|
34
|
+
cssVariable: "--font-serif",
|
|
35
|
+
fallbacks: ["serif"],
|
|
36
|
+
subsets: ["latin", "latin-ext"],
|
|
37
|
+
weights: [400, 700],
|
|
38
|
+
styles: ["normal"]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "JetBrains Mono",
|
|
42
|
+
cssVariable: "--font-mono",
|
|
43
|
+
fallbacks: ["monospace"],
|
|
44
|
+
subsets: ["latin", "latin-ext"],
|
|
45
|
+
weights: [400, 500, 700],
|
|
46
|
+
styles: ["normal"]
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
const provider = (options.fontProviders || fontProviders)?.fontsource
|
|
51
|
+
? (options.fontProviders || fontProviders).fontsource()
|
|
52
|
+
: undefined
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
fonts: (options.fonts || defaultFonts).map((font) => ({
|
|
56
|
+
...(provider ? { provider } : {}),
|
|
57
|
+
...font
|
|
58
|
+
}))
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function imagePreset(options = {}) {
|
|
63
|
+
const { domains = [], layout = "constrained", responsiveStyles = true } = options
|
|
64
|
+
return {
|
|
65
|
+
image: {
|
|
66
|
+
domains,
|
|
67
|
+
layout,
|
|
68
|
+
responsiveStyles
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function cloudflarePreset(options = {}) {
|
|
74
|
+
const { adapter = cloudflare(), cacheProvider = cacheCloudflare(), session = false } = options
|
|
75
|
+
return {
|
|
76
|
+
output: "server",
|
|
77
|
+
session,
|
|
78
|
+
adapter,
|
|
79
|
+
cache: { provider: cacheProvider }
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function discoverTranslations(dir = "./src/translations") {
|
|
84
|
+
const translations = {}
|
|
85
|
+
try {
|
|
86
|
+
const resolvedDir = path.resolve(process.cwd(), dir)
|
|
87
|
+
if (fs.existsSync(resolvedDir)) {
|
|
88
|
+
const files = fs.readdirSync(resolvedDir)
|
|
89
|
+
for (const file of files) {
|
|
90
|
+
if (file.endsWith(".json")) {
|
|
91
|
+
const locale = path.basename(file, ".json")
|
|
92
|
+
const content = JSON.parse(fs.readFileSync(path.join(resolvedDir, file), "utf8"))
|
|
93
|
+
translations[locale] = content
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} catch {}
|
|
98
|
+
return translations
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function discoverLogos(dir = "./src/assets/logos") {
|
|
102
|
+
try {
|
|
103
|
+
const candidateDirs = [dir, "./src/assets/logo"]
|
|
104
|
+
let resolvedDir = null
|
|
105
|
+
for (const d of candidateDirs) {
|
|
106
|
+
const p = path.resolve(process.cwd(), d)
|
|
107
|
+
if (fs.existsSync(p) && fs.statSync(p).isDirectory()) {
|
|
108
|
+
resolvedDir = p
|
|
109
|
+
break
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (!resolvedDir) return undefined
|
|
113
|
+
|
|
114
|
+
const files = fs.readdirSync(resolvedDir)
|
|
115
|
+
const logos = {}
|
|
116
|
+
|
|
117
|
+
const variants = ["logomark", "logotype", "logo"]
|
|
118
|
+
const modes = ["color", "white", "black", "light", "dark"]
|
|
119
|
+
const extensions = [".svg", ".png", ".webp", ".jpg", ".jpeg", ".gif"]
|
|
120
|
+
|
|
121
|
+
for (const variant of variants) {
|
|
122
|
+
for (const mode of modes) {
|
|
123
|
+
for (const ext of extensions) {
|
|
124
|
+
const fileName = `${variant}_${mode}${ext}`
|
|
125
|
+
if (files.includes(fileName)) {
|
|
126
|
+
if (!logos[variant]) logos[variant] = {}
|
|
127
|
+
const relPath = `./${path.relative(process.cwd(), path.join(resolvedDir, fileName)).replace(/\\/g, "/")}`
|
|
128
|
+
logos[variant][mode] = relPath
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
for (const ext of extensions) {
|
|
133
|
+
const fileName = `${variant}${ext}`
|
|
134
|
+
if (files.includes(fileName) && !logos[variant]) {
|
|
135
|
+
const relPath = `./${path.relative(process.cwd(), path.join(resolvedDir, fileName)).replace(/\\/g, "/")}`
|
|
136
|
+
logos[variant] = relPath
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return Object.keys(logos).length > 0 ? logos : undefined
|
|
142
|
+
} catch {
|
|
143
|
+
return undefined
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function defaultShortcuts() {
|
|
148
|
+
return {
|
|
149
|
+
categories: {
|
|
150
|
+
system: { label: "System" },
|
|
151
|
+
navigation: { label: "Navigation" }
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function rimelightIntegration(options, imageDomains, domain) {
|
|
157
|
+
return {
|
|
158
|
+
name: "rimelight-auto-plugins",
|
|
159
|
+
hooks: {
|
|
160
|
+
"astro:config:setup": async ({ updateConfig }) => {
|
|
161
|
+
const integrations = []
|
|
162
|
+
const plugins = []
|
|
163
|
+
|
|
164
|
+
if (options.solid) {
|
|
165
|
+
const solidMod = await import("@astrojs/solid-js")
|
|
166
|
+
const solidFn = solidMod.default || solidMod
|
|
167
|
+
const solidOpts =
|
|
168
|
+
typeof options.solid === "object"
|
|
169
|
+
? options.solid
|
|
170
|
+
: { include: ["**/solid/**", "**/*.tsx"] }
|
|
171
|
+
integrations.push(solidFn(solidOpts))
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (options.seo) {
|
|
175
|
+
const seoMod = await import("@rimelight/seo")
|
|
176
|
+
const { rimelightSeo } = seoMod
|
|
177
|
+
const seoOpts = typeof options.seo === "object" ? options.seo : {}
|
|
178
|
+
integrations.push(rimelightSeo(seoOpts))
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (options.cms) {
|
|
182
|
+
const cmsMod = await import("@rimelight/cms/integration")
|
|
183
|
+
const { rimelightCms } = cmsMod
|
|
184
|
+
const cmsOpts = typeof options.cms === "object" ? options.cms : {}
|
|
185
|
+
let storage = cmsOpts.storage
|
|
186
|
+
if (!storage) {
|
|
187
|
+
const storageMod = await import("@rimelight/cms/storage")
|
|
188
|
+
const { r2 } = storageMod
|
|
189
|
+
storage = r2({ binding: cmsOpts.binding || "BLOB" })
|
|
190
|
+
}
|
|
191
|
+
integrations.push(
|
|
192
|
+
rimelightCms({
|
|
193
|
+
storage,
|
|
194
|
+
auth: cmsOpts.auth || "./src/auth/auth.ts",
|
|
195
|
+
...cmsOpts
|
|
196
|
+
})
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (options.security) {
|
|
201
|
+
const secMod = await import("@rimelight/security")
|
|
202
|
+
const { security: securityFn } = secMod
|
|
203
|
+
const secOpts = typeof options.security === "object" ? options.security : {}
|
|
204
|
+
const defaultImgSrc = imageDomains.map((d) =>
|
|
205
|
+
d.startsWith("http://") || d.startsWith("https://") ? d : `https://${d}`
|
|
206
|
+
)
|
|
207
|
+
const imgSrc = secOpts.imgSrc
|
|
208
|
+
? Array.from(new Set([...defaultImgSrc, ...secOpts.imgSrc]))
|
|
209
|
+
: defaultImgSrc
|
|
210
|
+
|
|
211
|
+
plugins.push(
|
|
212
|
+
securityFn({
|
|
213
|
+
domain: secOpts.domain || domain,
|
|
214
|
+
imgSrc,
|
|
215
|
+
...secOpts
|
|
216
|
+
})
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (options.i18n) {
|
|
221
|
+
const i18nMod = await import("@rimelight/i18n")
|
|
222
|
+
const { i18n: i18nFn } = i18nMod
|
|
223
|
+
const i18nOpts = typeof options.i18n === "object" ? options.i18n : {}
|
|
224
|
+
const translations = i18nOpts.translations || discoverTranslations()
|
|
225
|
+
const locales = i18nOpts.locales || Object.keys(translations)
|
|
226
|
+
const defaultLocale = i18nOpts.defaultLocale || (locales.length > 0 ? locales[0] : "en")
|
|
227
|
+
const kvBinding =
|
|
228
|
+
i18nOpts.kvBinding ||
|
|
229
|
+
(domain ? `${domain.replaceAll(".", "-")}_translations` : undefined)
|
|
230
|
+
|
|
231
|
+
plugins.push(
|
|
232
|
+
i18nFn({
|
|
233
|
+
locales,
|
|
234
|
+
defaultLocale,
|
|
235
|
+
prefixDefaultLocale: i18nOpts.prefixDefaultLocale ?? true,
|
|
236
|
+
translations,
|
|
237
|
+
...(kvBinding ? { kvBinding } : {}),
|
|
238
|
+
...i18nOpts
|
|
239
|
+
})
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (options.ui) {
|
|
244
|
+
const uiMod = await import("@rimelight/ui")
|
|
245
|
+
const { ui: uiFn } = uiMod
|
|
246
|
+
const uiOpts = typeof options.ui === "object" ? options.ui : {}
|
|
247
|
+
const discoveredLogos = discoverLogos()
|
|
248
|
+
|
|
249
|
+
const mergedLogos = uiOpts.logos
|
|
250
|
+
? { ...discoveredLogos, ...uiOpts.logos }
|
|
251
|
+
: discoveredLogos
|
|
252
|
+
|
|
253
|
+
const mergedShortcuts =
|
|
254
|
+
uiOpts.shortcuts === false
|
|
255
|
+
? undefined
|
|
256
|
+
: {
|
|
257
|
+
...defaultShortcuts(),
|
|
258
|
+
...(typeof uiOpts.shortcuts === "object" ? uiOpts.shortcuts : {})
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
plugins.push(
|
|
262
|
+
uiFn({
|
|
263
|
+
...(mergedLogos ? { logos: mergedLogos } : {}),
|
|
264
|
+
...(mergedShortcuts ? { shortcuts: mergedShortcuts } : {}),
|
|
265
|
+
...uiOpts
|
|
266
|
+
})
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
updateConfig({
|
|
271
|
+
integrations,
|
|
272
|
+
vite: {
|
|
273
|
+
plugins
|
|
274
|
+
}
|
|
275
|
+
})
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export function rimelightAstroConfig(options = {}) {
|
|
282
|
+
const {
|
|
283
|
+
domain,
|
|
284
|
+
site = domain ? `https://${domain}` : undefined,
|
|
285
|
+
imageDomains = domain ? [domain, `cdn.${domain}`, "cdn.rimelight.com"] : [],
|
|
286
|
+
apiSwrSeconds = 600,
|
|
287
|
+
pageMaxAgeSeconds = 300,
|
|
288
|
+
adapter,
|
|
289
|
+
cacheProvider,
|
|
290
|
+
fonts,
|
|
291
|
+
solid,
|
|
292
|
+
security,
|
|
293
|
+
i18n,
|
|
294
|
+
cms,
|
|
295
|
+
ui,
|
|
296
|
+
seo,
|
|
297
|
+
integrations = [],
|
|
298
|
+
vite = {},
|
|
299
|
+
...rest
|
|
300
|
+
} = options
|
|
301
|
+
|
|
302
|
+
const hasFlags = Boolean(solid || security || i18n || cms || ui || seo)
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
...(site ? { site } : {}),
|
|
306
|
+
prefetch: {
|
|
307
|
+
prefetchAll: true
|
|
308
|
+
},
|
|
309
|
+
...cloudflarePreset({
|
|
310
|
+
...(adapter !== undefined ? { adapter } : {}),
|
|
311
|
+
...(cacheProvider !== undefined ? { cacheProvider } : {})
|
|
312
|
+
}),
|
|
313
|
+
...cacheRulesPreset({
|
|
314
|
+
...(apiSwrSeconds !== undefined ? { apiSwrSeconds } : {}),
|
|
315
|
+
...(pageMaxAgeSeconds !== undefined ? { pageMaxAgeSeconds } : {})
|
|
316
|
+
}),
|
|
317
|
+
...fontsPreset(fonts !== undefined ? { fonts } : {}),
|
|
318
|
+
...imagePreset({ domains: imageDomains }),
|
|
319
|
+
markdown: {
|
|
320
|
+
syntaxHighlight: "prism"
|
|
321
|
+
},
|
|
322
|
+
integrations: [
|
|
323
|
+
...(hasFlags ? [rimelightIntegration(options, imageDomains, domain)] : []),
|
|
324
|
+
...integrations
|
|
325
|
+
],
|
|
326
|
+
vite,
|
|
327
|
+
...rest
|
|
328
|
+
}
|
|
329
|
+
}
|
package/astro/index.ts
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import fs from "node:fs"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import cloudflare from "@astrojs/cloudflare"
|
|
4
|
+
import { cacheCloudflare } from "@astrojs/cloudflare/cache"
|
|
5
|
+
import { fontProviders } from "astro/config"
|
|
6
|
+
|
|
7
|
+
export interface CacheRulesPresetOptions {
|
|
8
|
+
apiSwrSeconds?: number
|
|
9
|
+
pageMaxAgeSeconds?: number
|
|
10
|
+
customRules?: Record<string, any>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function cacheRulesPreset(options: CacheRulesPresetOptions = {}): any {
|
|
14
|
+
const { apiSwrSeconds = 600, pageMaxAgeSeconds = 300, customRules = {} } = options
|
|
15
|
+
return {
|
|
16
|
+
routeRules: {
|
|
17
|
+
"/api/[...path]": {
|
|
18
|
+
swr: apiSwrSeconds
|
|
19
|
+
},
|
|
20
|
+
"/[...path]": {
|
|
21
|
+
maxAge: pageMaxAgeSeconds
|
|
22
|
+
},
|
|
23
|
+
...customRules
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface FontsPresetOptions {
|
|
29
|
+
fontProviders?: any
|
|
30
|
+
fonts?: any[]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function fontsPreset(options: FontsPresetOptions = {}): any {
|
|
34
|
+
const defaultFonts = [
|
|
35
|
+
{
|
|
36
|
+
name: "Noto Sans",
|
|
37
|
+
cssVariable: "--font-sans",
|
|
38
|
+
fallbacks: ["sans-serif"],
|
|
39
|
+
subsets: ["latin", "latin-ext"],
|
|
40
|
+
weights: [400, 500, 600, 700],
|
|
41
|
+
styles: ["normal"]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "Noto Serif",
|
|
45
|
+
cssVariable: "--font-serif",
|
|
46
|
+
fallbacks: ["serif"],
|
|
47
|
+
subsets: ["latin", "latin-ext"],
|
|
48
|
+
weights: [400, 700],
|
|
49
|
+
styles: ["normal"]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "JetBrains Mono",
|
|
53
|
+
cssVariable: "--font-mono",
|
|
54
|
+
fallbacks: ["monospace"],
|
|
55
|
+
subsets: ["latin", "latin-ext"],
|
|
56
|
+
weights: [400, 500, 700],
|
|
57
|
+
styles: ["normal"]
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
const provider = (options.fontProviders || fontProviders)?.fontsource
|
|
62
|
+
? (options.fontProviders || fontProviders).fontsource()
|
|
63
|
+
: undefined
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
fonts: (options.fonts || defaultFonts).map((font) => ({
|
|
67
|
+
...(provider ? { provider } : {}),
|
|
68
|
+
...font
|
|
69
|
+
}))
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface ImagePresetOptions {
|
|
74
|
+
domains?: string[]
|
|
75
|
+
layout?: "constrained" | "fixed" | "full-width" | "responsive"
|
|
76
|
+
responsiveStyles?: boolean
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function imagePreset(options: ImagePresetOptions = {}): any {
|
|
80
|
+
const { domains = [], layout = "constrained", responsiveStyles = true } = options
|
|
81
|
+
return {
|
|
82
|
+
image: {
|
|
83
|
+
domains,
|
|
84
|
+
layout,
|
|
85
|
+
responsiveStyles
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface CloudflarePresetOptions {
|
|
91
|
+
adapter?: any
|
|
92
|
+
cacheProvider?: any
|
|
93
|
+
session?: boolean
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function cloudflarePreset(options: CloudflarePresetOptions = {}): any {
|
|
97
|
+
const { adapter = cloudflare(), cacheProvider = cacheCloudflare(), session = false } = options
|
|
98
|
+
return {
|
|
99
|
+
output: "server" as const,
|
|
100
|
+
session,
|
|
101
|
+
adapter,
|
|
102
|
+
cache: { provider: cacheProvider }
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface RimelightAstroOptions {
|
|
107
|
+
domain?: string
|
|
108
|
+
site?: string
|
|
109
|
+
imageDomains?: string[]
|
|
110
|
+
apiSwrSeconds?: number
|
|
111
|
+
pageMaxAgeSeconds?: number
|
|
112
|
+
adapter?: any
|
|
113
|
+
cacheProvider?: any
|
|
114
|
+
fonts?: any[]
|
|
115
|
+
solid?: boolean | { include?: string[]; [key: string]: any }
|
|
116
|
+
security?:
|
|
117
|
+
| boolean
|
|
118
|
+
| {
|
|
119
|
+
domain?: string
|
|
120
|
+
imgSrc?: string[]
|
|
121
|
+
directives?: Record<string, any>
|
|
122
|
+
[key: string]: any
|
|
123
|
+
}
|
|
124
|
+
i18n?:
|
|
125
|
+
| boolean
|
|
126
|
+
| {
|
|
127
|
+
translations?: Record<string, any>
|
|
128
|
+
locales?: string[]
|
|
129
|
+
defaultLocale?: string
|
|
130
|
+
prefixDefaultLocale?: boolean
|
|
131
|
+
kvBinding?: string
|
|
132
|
+
[key: string]: any
|
|
133
|
+
}
|
|
134
|
+
seo?:
|
|
135
|
+
| boolean
|
|
136
|
+
| {
|
|
137
|
+
robots?: boolean | Record<string, any>
|
|
138
|
+
sitemap?: boolean | Record<string, any>
|
|
139
|
+
llms?: boolean | Record<string, any>
|
|
140
|
+
[key: string]: any
|
|
141
|
+
}
|
|
142
|
+
cms?:
|
|
143
|
+
| boolean
|
|
144
|
+
| {
|
|
145
|
+
storage?: any
|
|
146
|
+
binding?: string
|
|
147
|
+
auth?: string
|
|
148
|
+
[key: string]: any
|
|
149
|
+
}
|
|
150
|
+
ui?:
|
|
151
|
+
| boolean
|
|
152
|
+
| {
|
|
153
|
+
logos?: any
|
|
154
|
+
shortcuts?: any
|
|
155
|
+
[key: string]: any
|
|
156
|
+
}
|
|
157
|
+
integrations?: any[]
|
|
158
|
+
vite?: {
|
|
159
|
+
plugins?: any[]
|
|
160
|
+
[key: string]: any
|
|
161
|
+
}
|
|
162
|
+
[key: string]: any
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function discoverTranslations(dir = "./src/translations"): Record<string, any> {
|
|
166
|
+
const translations: Record<string, any> = {}
|
|
167
|
+
try {
|
|
168
|
+
const resolvedDir = path.resolve(process.cwd(), dir)
|
|
169
|
+
if (fs.existsSync(resolvedDir)) {
|
|
170
|
+
const files = fs.readdirSync(resolvedDir)
|
|
171
|
+
for (const file of files) {
|
|
172
|
+
if (file.endsWith(".json")) {
|
|
173
|
+
const locale = path.basename(file, ".json")
|
|
174
|
+
const content = JSON.parse(fs.readFileSync(path.join(resolvedDir, file), "utf8"))
|
|
175
|
+
translations[locale] = content
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
} catch {}
|
|
180
|
+
return translations
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function discoverLogos(dir = "./src/assets/logos"): Record<string, any> | undefined {
|
|
184
|
+
try {
|
|
185
|
+
const candidateDirs = [dir, "./src/assets/logo"]
|
|
186
|
+
let resolvedDir: string | null = null
|
|
187
|
+
for (const d of candidateDirs) {
|
|
188
|
+
const p = path.resolve(process.cwd(), d)
|
|
189
|
+
if (fs.existsSync(p) && fs.statSync(p).isDirectory()) {
|
|
190
|
+
resolvedDir = p
|
|
191
|
+
break
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (!resolvedDir) return undefined
|
|
195
|
+
|
|
196
|
+
const files = fs.readdirSync(resolvedDir)
|
|
197
|
+
const logos: Record<string, any> = {}
|
|
198
|
+
|
|
199
|
+
const variants = ["logomark", "logotype", "logo"]
|
|
200
|
+
const modes = ["color", "white", "black", "light", "dark"]
|
|
201
|
+
const extensions = [".svg", ".png", ".webp", ".jpg", ".jpeg", ".gif"]
|
|
202
|
+
|
|
203
|
+
for (const variant of variants) {
|
|
204
|
+
for (const mode of modes) {
|
|
205
|
+
for (const ext of extensions) {
|
|
206
|
+
const fileName = `${variant}_${mode}${ext}`
|
|
207
|
+
if (files.includes(fileName)) {
|
|
208
|
+
if (!logos[variant]) logos[variant] = {}
|
|
209
|
+
const relPath = `./${path.relative(process.cwd(), path.join(resolvedDir, fileName)).replace(/\\/g, "/")}`
|
|
210
|
+
logos[variant][mode] = relPath
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
for (const ext of extensions) {
|
|
215
|
+
const fileName = `${variant}${ext}`
|
|
216
|
+
if (files.includes(fileName) && !logos[variant]) {
|
|
217
|
+
const relPath = `./${path.relative(process.cwd(), path.join(resolvedDir, fileName)).replace(/\\/g, "/")}`
|
|
218
|
+
logos[variant] = relPath
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return Object.keys(logos).length > 0 ? logos : undefined
|
|
224
|
+
} catch {
|
|
225
|
+
return undefined
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function defaultShortcuts(): Record<string, any> {
|
|
230
|
+
return {
|
|
231
|
+
categories: {
|
|
232
|
+
system: { label: "System" },
|
|
233
|
+
navigation: { label: "Navigation" }
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function rimelightIntegration(
|
|
239
|
+
options: RimelightAstroOptions,
|
|
240
|
+
imageDomains: string[],
|
|
241
|
+
domain?: string
|
|
242
|
+
) {
|
|
243
|
+
return {
|
|
244
|
+
name: "rimelight-auto-plugins",
|
|
245
|
+
hooks: {
|
|
246
|
+
"astro:config:setup": async ({ updateConfig }: { updateConfig: (config: any) => void }) => {
|
|
247
|
+
const integrations: any[] = []
|
|
248
|
+
const plugins: any[] = []
|
|
249
|
+
|
|
250
|
+
if (options.solid) {
|
|
251
|
+
const solidMod = await import("@astrojs/solid-js")
|
|
252
|
+
const solidFn = (solidMod as any).default || solidMod
|
|
253
|
+
const solidOpts =
|
|
254
|
+
typeof options.solid === "object"
|
|
255
|
+
? options.solid
|
|
256
|
+
: { include: ["**/solid/**", "**/*.tsx"] }
|
|
257
|
+
integrations.push(solidFn(solidOpts))
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (options.seo) {
|
|
261
|
+
const seoMod = await import("@rimelight/seo")
|
|
262
|
+
const { rimelightSeo } = seoMod as any
|
|
263
|
+
const seoOpts = typeof options.seo === "object" ? options.seo : {}
|
|
264
|
+
integrations.push(rimelightSeo(seoOpts))
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (options.cms) {
|
|
268
|
+
const cmsMod = await import("@rimelight/cms/integration")
|
|
269
|
+
const { rimelightCms } = cmsMod as any
|
|
270
|
+
const cmsOpts = typeof options.cms === "object" ? options.cms : {}
|
|
271
|
+
let storage = cmsOpts.storage
|
|
272
|
+
if (!storage) {
|
|
273
|
+
const storageMod = await import("@rimelight/cms/storage")
|
|
274
|
+
const { r2 } = storageMod as any
|
|
275
|
+
storage = r2({ binding: cmsOpts.binding || "BLOB" })
|
|
276
|
+
}
|
|
277
|
+
integrations.push(
|
|
278
|
+
rimelightCms({
|
|
279
|
+
storage,
|
|
280
|
+
auth: cmsOpts.auth || "./src/auth/auth.ts",
|
|
281
|
+
...cmsOpts
|
|
282
|
+
})
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (options.security) {
|
|
287
|
+
const secMod = await import("@rimelight/security")
|
|
288
|
+
const { security: securityFn } = secMod as any
|
|
289
|
+
const secOpts = typeof options.security === "object" ? options.security : {}
|
|
290
|
+
const defaultImgSrc = imageDomains.map((d: string) =>
|
|
291
|
+
d.startsWith("http://") || d.startsWith("https://") ? d : `https://${d}`
|
|
292
|
+
)
|
|
293
|
+
const imgSrc = secOpts.imgSrc
|
|
294
|
+
? Array.from(new Set([...defaultImgSrc, ...secOpts.imgSrc]))
|
|
295
|
+
: defaultImgSrc
|
|
296
|
+
|
|
297
|
+
plugins.push(
|
|
298
|
+
securityFn({
|
|
299
|
+
domain: secOpts.domain || domain,
|
|
300
|
+
imgSrc,
|
|
301
|
+
...secOpts
|
|
302
|
+
})
|
|
303
|
+
)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (options.i18n) {
|
|
307
|
+
const i18nMod = await import("@rimelight/i18n")
|
|
308
|
+
const { i18n: i18nFn } = i18nMod as any
|
|
309
|
+
const i18nOpts = typeof options.i18n === "object" ? options.i18n : {}
|
|
310
|
+
const translations = i18nOpts.translations || discoverTranslations()
|
|
311
|
+
const locales = i18nOpts.locales || Object.keys(translations)
|
|
312
|
+
const defaultLocale = i18nOpts.defaultLocale || (locales.length > 0 ? locales[0] : "en")
|
|
313
|
+
const kvBinding =
|
|
314
|
+
i18nOpts.kvBinding ||
|
|
315
|
+
(domain ? `${domain.replaceAll(".", "-")}_translations` : undefined)
|
|
316
|
+
|
|
317
|
+
plugins.push(
|
|
318
|
+
i18nFn({
|
|
319
|
+
locales,
|
|
320
|
+
defaultLocale,
|
|
321
|
+
prefixDefaultLocale: i18nOpts.prefixDefaultLocale ?? true,
|
|
322
|
+
translations,
|
|
323
|
+
...(kvBinding ? { kvBinding } : {}),
|
|
324
|
+
...i18nOpts
|
|
325
|
+
})
|
|
326
|
+
)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (options.ui) {
|
|
330
|
+
const uiMod = await import("@rimelight/ui")
|
|
331
|
+
const { ui: uiFn } = uiMod as any
|
|
332
|
+
const uiOpts = typeof options.ui === "object" ? options.ui : {}
|
|
333
|
+
const discoveredLogos = discoverLogos()
|
|
334
|
+
|
|
335
|
+
const mergedLogos = uiOpts.logos
|
|
336
|
+
? { ...discoveredLogos, ...uiOpts.logos }
|
|
337
|
+
: discoveredLogos
|
|
338
|
+
|
|
339
|
+
const mergedShortcuts =
|
|
340
|
+
uiOpts.shortcuts === false
|
|
341
|
+
? undefined
|
|
342
|
+
: {
|
|
343
|
+
...defaultShortcuts(),
|
|
344
|
+
...(typeof uiOpts.shortcuts === "object" ? uiOpts.shortcuts : {})
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
plugins.push(
|
|
348
|
+
uiFn({
|
|
349
|
+
...(mergedLogos ? { logos: mergedLogos } : {}),
|
|
350
|
+
...(mergedShortcuts ? { shortcuts: mergedShortcuts } : {}),
|
|
351
|
+
...uiOpts
|
|
352
|
+
})
|
|
353
|
+
)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
updateConfig({
|
|
357
|
+
integrations,
|
|
358
|
+
vite: {
|
|
359
|
+
plugins
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export function rimelightAstroConfig(options: RimelightAstroOptions = {}): any {
|
|
368
|
+
const {
|
|
369
|
+
domain,
|
|
370
|
+
site = domain ? `https://${domain}` : undefined,
|
|
371
|
+
imageDomains = domain ? [domain, `cdn.${domain}`, "cdn.rimelight.com"] : [],
|
|
372
|
+
apiSwrSeconds = 600,
|
|
373
|
+
pageMaxAgeSeconds = 300,
|
|
374
|
+
adapter,
|
|
375
|
+
cacheProvider,
|
|
376
|
+
fonts,
|
|
377
|
+
solid,
|
|
378
|
+
security,
|
|
379
|
+
i18n,
|
|
380
|
+
cms,
|
|
381
|
+
ui,
|
|
382
|
+
seo,
|
|
383
|
+
integrations = [],
|
|
384
|
+
vite = {},
|
|
385
|
+
...rest
|
|
386
|
+
} = options
|
|
387
|
+
|
|
388
|
+
const hasFlags = Boolean(solid || security || i18n || cms || ui || seo)
|
|
389
|
+
|
|
390
|
+
return {
|
|
391
|
+
...(site ? { site } : {}),
|
|
392
|
+
prefetch: {
|
|
393
|
+
prefetchAll: true
|
|
394
|
+
},
|
|
395
|
+
...cloudflarePreset({
|
|
396
|
+
...(adapter !== undefined ? { adapter } : {}),
|
|
397
|
+
...(cacheProvider !== undefined ? { cacheProvider } : {})
|
|
398
|
+
}),
|
|
399
|
+
...cacheRulesPreset({
|
|
400
|
+
...(apiSwrSeconds !== undefined ? { apiSwrSeconds } : {}),
|
|
401
|
+
...(pageMaxAgeSeconds !== undefined ? { pageMaxAgeSeconds } : {})
|
|
402
|
+
}),
|
|
403
|
+
...fontsPreset(fonts !== undefined ? { fonts } : {}),
|
|
404
|
+
...imagePreset({ domains: imageDomains }),
|
|
405
|
+
markdown: {
|
|
406
|
+
syntaxHighlight: "prism" as const
|
|
407
|
+
},
|
|
408
|
+
integrations: [
|
|
409
|
+
...(hasFlags ? [rimelightIntegration(options, imageDomains, domain)] : []),
|
|
410
|
+
...integrations
|
|
411
|
+
],
|
|
412
|
+
vite,
|
|
413
|
+
...rest
|
|
414
|
+
}
|
|
415
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rimelight/config",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Rimelight Entertainment's shared configuration package",
|
|
6
6
|
"homepage": "https://rimelight.com/docs",
|
|
@@ -18,25 +18,69 @@
|
|
|
18
18
|
"files": [
|
|
19
19
|
"tsconfig",
|
|
20
20
|
"vite-plus",
|
|
21
|
+
"astro",
|
|
21
22
|
"src"
|
|
22
23
|
],
|
|
23
24
|
"type": "module",
|
|
24
25
|
"exports": {
|
|
25
26
|
"./tsconfig/base": "./tsconfig/base.json",
|
|
26
|
-
"./tsconfig/
|
|
27
|
+
"./tsconfig/astro": "./tsconfig/astro.json",
|
|
28
|
+
"./tsconfig/astro-solid": "./tsconfig/astro-solid.json",
|
|
27
29
|
"./vite-plus/base": {
|
|
28
30
|
"types": "./vite-plus/base.ts",
|
|
29
31
|
"default": "./vite-plus/base.js"
|
|
32
|
+
},
|
|
33
|
+
"./astro": {
|
|
34
|
+
"types": "./astro/index.ts",
|
|
35
|
+
"default": "./astro/index.js"
|
|
30
36
|
}
|
|
31
37
|
},
|
|
32
38
|
"publishConfig": {
|
|
33
39
|
"access": "public"
|
|
34
40
|
},
|
|
35
41
|
"devDependencies": {
|
|
42
|
+
"@astrojs/cloudflare": "14.3.1",
|
|
43
|
+
"astro": "7.3.2",
|
|
36
44
|
"typescript": "6.0.3",
|
|
37
|
-
"vite-plus": "0.3.
|
|
45
|
+
"vite-plus": "0.3.1"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"@astrojs/cloudflare": ">=14.0.0",
|
|
49
|
+
"@astrojs/solid-js": ">=7.0.0",
|
|
50
|
+
"@rimelight/cms": ">=0.0.1",
|
|
51
|
+
"@rimelight/i18n": ">=0.0.1",
|
|
52
|
+
"@rimelight/security": ">=0.0.1",
|
|
53
|
+
"@rimelight/seo": ">=0.0.1",
|
|
54
|
+
"@rimelight/ui": ">=0.0.1",
|
|
55
|
+
"astro": ">=7.0.0"
|
|
56
|
+
},
|
|
57
|
+
"peerDependenciesMeta": {
|
|
58
|
+
"@astrojs/cloudflare": {
|
|
59
|
+
"optional": true
|
|
60
|
+
},
|
|
61
|
+
"@astrojs/solid-js": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"@rimelight/cms": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"@rimelight/i18n": {
|
|
68
|
+
"optional": true
|
|
69
|
+
},
|
|
70
|
+
"@rimelight/security": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"@rimelight/seo": {
|
|
74
|
+
"optional": true
|
|
75
|
+
},
|
|
76
|
+
"@rimelight/ui": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"astro": {
|
|
80
|
+
"optional": true
|
|
81
|
+
}
|
|
38
82
|
},
|
|
39
83
|
"engines": {
|
|
40
|
-
"node": ">=26.
|
|
84
|
+
"node": ">=26.8.2"
|
|
41
85
|
}
|
|
42
86
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
-
"display": "Rimelight SolidJS",
|
|
4
|
-
"extends": "./base.json",
|
|
5
3
|
"compilerOptions": {
|
|
6
4
|
"jsx": "preserve",
|
|
7
5
|
"jsxImportSource": "solid-js"
|
|
8
|
-
}
|
|
6
|
+
},
|
|
7
|
+
"display": "Rimelight Astro + SolidJS",
|
|
8
|
+
"extends": "./astro.json"
|
|
9
9
|
}
|
package/tsconfig/base.json
CHANGED
|
@@ -1,31 +1,33 @@
|
|
|
1
1
|
{
|
|
2
|
-
"exclude": ["dist"],
|
|
3
2
|
"compilerOptions": {
|
|
4
|
-
"
|
|
5
|
-
"module": "ESNext",
|
|
6
|
-
"moduleResolution": "bundler",
|
|
7
|
-
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
8
|
-
"types": ["node"],
|
|
3
|
+
"allowArbitraryExtensions": true,
|
|
9
4
|
"allowImportingTsExtensions": true,
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"noEmit": true,
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"allowUnreachableCode": false,
|
|
7
|
+
"allowUnusedLabels": false,
|
|
14
8
|
"esModuleInterop": true,
|
|
9
|
+
"exactOptionalPropertyTypes": true,
|
|
15
10
|
"forceConsistentCasingInFileNames": true,
|
|
16
|
-
"
|
|
17
|
-
"skipLibCheck": true,
|
|
18
|
-
"allowJs": true,
|
|
11
|
+
"isolatedModules": true,
|
|
19
12
|
"jsx": "preserve",
|
|
20
|
-
"
|
|
13
|
+
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
14
|
+
"module": "ESNext",
|
|
15
|
+
"moduleResolution": "bundler",
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
"noErrorTruncation": true,
|
|
21
18
|
"noFallthroughCasesInSwitch": true,
|
|
22
19
|
"noImplicitOverride": true,
|
|
23
20
|
"noImplicitReturns": true,
|
|
21
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
22
|
+
"noUncheckedIndexedAccess": true,
|
|
23
|
+
"noUncheckedSideEffectImports": true,
|
|
24
24
|
"noUnusedLocals": true,
|
|
25
25
|
"noUnusedParameters": true,
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
26
|
+
"resolveJsonModule": true,
|
|
27
|
+
"skipLibCheck": true,
|
|
28
|
+
"strict": true,
|
|
29
|
+
"target": "ESNext",
|
|
30
|
+
"types": ["node"],
|
|
31
|
+
"verbatimModuleSyntax": true
|
|
30
32
|
}
|
|
31
33
|
}
|
package/vite-plus/base.js
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
import fs from "node:fs"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
|
|
4
|
+
export function findSourceEntries(baseDir = "src") {
|
|
5
|
+
if (!fs.existsSync(baseDir)) {
|
|
6
|
+
return []
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const entries = []
|
|
10
|
+
|
|
11
|
+
function walk(currentDir) {
|
|
12
|
+
const files = fs.readdirSync(currentDir, { withFileTypes: true })
|
|
13
|
+
for (const file of files) {
|
|
14
|
+
const fullPath = path.join(currentDir, file.name)
|
|
15
|
+
if (file.isDirectory()) {
|
|
16
|
+
walk(fullPath)
|
|
17
|
+
} else if (file.isFile()) {
|
|
18
|
+
const normalized = fullPath.split(path.sep).join("/")
|
|
19
|
+
if (
|
|
20
|
+
(file.name.endsWith(".ts") ||
|
|
21
|
+
file.name.endsWith(".tsx") ||
|
|
22
|
+
file.name.endsWith(".js") ||
|
|
23
|
+
file.name.endsWith(".jsx")) &&
|
|
24
|
+
!file.name.endsWith(".d.ts") &&
|
|
25
|
+
!file.name.endsWith(".test.ts") &&
|
|
26
|
+
!file.name.endsWith(".test.tsx") &&
|
|
27
|
+
!file.name.endsWith(".spec.ts") &&
|
|
28
|
+
!file.name.endsWith(".spec.tsx")
|
|
29
|
+
) {
|
|
30
|
+
entries.push(normalized)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
walk(baseDir)
|
|
37
|
+
return entries.sort((a, b) => a.localeCompare(b))
|
|
38
|
+
}
|
|
39
|
+
|
|
1
40
|
export function rimelightConfig() {
|
|
2
41
|
return {
|
|
3
42
|
lint: {
|
|
@@ -17,18 +56,99 @@ export function rimelightConfig() {
|
|
|
17
56
|
},
|
|
18
57
|
staged: {
|
|
19
58
|
"*": "vp check --fix"
|
|
59
|
+
},
|
|
60
|
+
test: {
|
|
61
|
+
environment: "node"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function findPackageExternals(pkgJsonPath = "package.json") {
|
|
67
|
+
try {
|
|
68
|
+
const fullPath = path.resolve(process.cwd(), pkgJsonPath)
|
|
69
|
+
if (!fs.existsSync(fullPath)) return ["@rimelight/*"]
|
|
70
|
+
const pkg = JSON.parse(fs.readFileSync(fullPath, "utf8"))
|
|
71
|
+
const externals = new Set()
|
|
72
|
+
|
|
73
|
+
if (pkg.peerDependencies) {
|
|
74
|
+
Object.keys(pkg.peerDependencies).forEach((dep) => externals.add(dep))
|
|
20
75
|
}
|
|
76
|
+
if (pkg.dependencies) {
|
|
77
|
+
Object.keys(pkg.dependencies).forEach((dep) => externals.add(dep))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return Array.from(externals)
|
|
81
|
+
} catch {
|
|
82
|
+
return []
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function verifyPackageExports(pkgJsonPath = "package.json", srcDir = "src") {
|
|
87
|
+
try {
|
|
88
|
+
const fullPath = path.resolve(process.cwd(), pkgJsonPath)
|
|
89
|
+
if (!fs.existsSync(fullPath)) {
|
|
90
|
+
return { valid: false, missingExports: ["package.json not found"], extraExports: [] }
|
|
91
|
+
}
|
|
92
|
+
const pkg = JSON.parse(fs.readFileSync(fullPath, "utf8"))
|
|
93
|
+
const exportsMap = pkg.exports || {}
|
|
94
|
+
const sourceEntries = findSourceEntries(srcDir)
|
|
95
|
+
|
|
96
|
+
const expectedKeys = sourceEntries.map((file) => {
|
|
97
|
+
const rel = file.replace(new RegExp(`^${srcDir}/`), "").replace(/\.(ts|tsx|js|jsx)$/, "")
|
|
98
|
+
return rel === "index" ? "." : `./${rel}`
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
const definedKeys = Object.keys(exportsMap)
|
|
102
|
+
const missingExports = expectedKeys.filter(
|
|
103
|
+
(k) => !definedKeys.includes(k) && !definedKeys.includes("./*")
|
|
104
|
+
)
|
|
105
|
+
const extraExports = definedKeys.filter(
|
|
106
|
+
(k) => k !== "." && k !== "./*" && !k.includes("*") && !expectedKeys.includes(k)
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
valid: missingExports.length === 0,
|
|
111
|
+
missingExports,
|
|
112
|
+
extraExports
|
|
113
|
+
}
|
|
114
|
+
} catch (err) {
|
|
115
|
+
return { valid: false, missingExports: [err.message], extraExports: [] }
|
|
21
116
|
}
|
|
22
117
|
}
|
|
23
118
|
|
|
24
119
|
export function rimelightPackConfig(options = {}) {
|
|
25
|
-
const { entry
|
|
120
|
+
const { entry, autoEntry, pack = {}, autoExternal = true, ...rest } = options
|
|
121
|
+
|
|
122
|
+
let resolvedEntry = ["src/index.ts"]
|
|
123
|
+
|
|
124
|
+
if (Array.isArray(entry)) {
|
|
125
|
+
resolvedEntry = entry
|
|
126
|
+
} else if (entry === "auto" || autoEntry) {
|
|
127
|
+
const dir = typeof autoEntry === "string" ? autoEntry : "src"
|
|
128
|
+
const discovered = findSourceEntries(dir)
|
|
129
|
+
if (discovered.length > 0) {
|
|
130
|
+
resolvedEntry = discovered
|
|
131
|
+
}
|
|
132
|
+
} else if (typeof entry === "string") {
|
|
133
|
+
resolvedEntry = [entry]
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const discoveredExternals = autoExternal ? findPackageExternals() : []
|
|
137
|
+
const userExternal = pack["external"] || []
|
|
138
|
+
const userExternalList = Array.isArray(userExternal) ? userExternal : [userExternal]
|
|
139
|
+
const userNeverBundle = pack["deps"]?.["neverBundle"] || []
|
|
140
|
+
const userNeverBundleList = Array.isArray(userNeverBundle) ? userNeverBundle : [userNeverBundle]
|
|
141
|
+
const mergedExternal = Array.from(
|
|
142
|
+
new Set([...userExternalList, ...userNeverBundleList, ...discoveredExternals])
|
|
143
|
+
).filter(Boolean)
|
|
144
|
+
|
|
26
145
|
return {
|
|
27
146
|
...rimelightConfig(),
|
|
28
147
|
...rest,
|
|
29
148
|
pack: {
|
|
30
|
-
entry,
|
|
149
|
+
entry: resolvedEntry,
|
|
31
150
|
dts: true,
|
|
151
|
+
...(mergedExternal.length > 0 ? { deps: { neverBundle: mergedExternal } } : {}),
|
|
32
152
|
...pack
|
|
33
153
|
}
|
|
34
154
|
}
|
package/vite-plus/base.ts
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
|
+
import fs from "node:fs"
|
|
2
|
+
import path from "node:path"
|
|
1
3
|
import type { UserConfig } from "vite-plus"
|
|
2
4
|
|
|
5
|
+
export function findSourceEntries(baseDir = "src"): string[] {
|
|
6
|
+
if (!fs.existsSync(baseDir)) {
|
|
7
|
+
return []
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const entries: string[] = []
|
|
11
|
+
|
|
12
|
+
function walk(currentDir: string) {
|
|
13
|
+
const files = fs.readdirSync(currentDir, { withFileTypes: true })
|
|
14
|
+
for (const file of files) {
|
|
15
|
+
const fullPath = path.join(currentDir, file.name)
|
|
16
|
+
if (file.isDirectory()) {
|
|
17
|
+
walk(fullPath)
|
|
18
|
+
} else if (file.isFile()) {
|
|
19
|
+
const normalized = fullPath.split(path.sep).join("/")
|
|
20
|
+
if (
|
|
21
|
+
(file.name.endsWith(".ts") ||
|
|
22
|
+
file.name.endsWith(".tsx") ||
|
|
23
|
+
file.name.endsWith(".js") ||
|
|
24
|
+
file.name.endsWith(".jsx")) &&
|
|
25
|
+
!file.name.endsWith(".d.ts") &&
|
|
26
|
+
!file.name.endsWith(".test.ts") &&
|
|
27
|
+
!file.name.endsWith(".test.tsx") &&
|
|
28
|
+
!file.name.endsWith(".spec.ts") &&
|
|
29
|
+
!file.name.endsWith(".spec.tsx")
|
|
30
|
+
) {
|
|
31
|
+
entries.push(normalized)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
walk(baseDir)
|
|
38
|
+
return entries.sort((a, b) => a.localeCompare(b))
|
|
39
|
+
}
|
|
40
|
+
|
|
3
41
|
export function rimelightConfig(): UserConfig {
|
|
4
42
|
return {
|
|
5
43
|
lint: {
|
|
@@ -19,20 +57,116 @@ export function rimelightConfig(): UserConfig {
|
|
|
19
57
|
},
|
|
20
58
|
staged: {
|
|
21
59
|
"*": "vp check --fix"
|
|
60
|
+
},
|
|
61
|
+
test: {
|
|
62
|
+
environment: "node"
|
|
22
63
|
}
|
|
23
64
|
}
|
|
24
65
|
}
|
|
25
66
|
|
|
26
|
-
export function
|
|
27
|
-
|
|
28
|
-
)
|
|
29
|
-
|
|
67
|
+
export function findPackageExternals(pkgJsonPath = "package.json"): string[] {
|
|
68
|
+
try {
|
|
69
|
+
const fullPath = path.resolve(process.cwd(), pkgJsonPath)
|
|
70
|
+
if (!fs.existsSync(fullPath)) return ["@rimelight/*"]
|
|
71
|
+
const pkg = JSON.parse(fs.readFileSync(fullPath, "utf8"))
|
|
72
|
+
const externals = new Set<string>()
|
|
73
|
+
|
|
74
|
+
if (pkg.peerDependencies) {
|
|
75
|
+
Object.keys(pkg.peerDependencies).forEach((dep) => externals.add(dep))
|
|
76
|
+
}
|
|
77
|
+
if (pkg.dependencies) {
|
|
78
|
+
Object.keys(pkg.dependencies).forEach((dep) => externals.add(dep))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return Array.from(externals)
|
|
82
|
+
} catch {
|
|
83
|
+
return []
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface ExportValidationResult {
|
|
88
|
+
valid: boolean
|
|
89
|
+
missingExports: string[]
|
|
90
|
+
extraExports: string[]
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function verifyPackageExports(
|
|
94
|
+
pkgJsonPath = "package.json",
|
|
95
|
+
srcDir = "src"
|
|
96
|
+
): ExportValidationResult {
|
|
97
|
+
try {
|
|
98
|
+
const fullPath = path.resolve(process.cwd(), pkgJsonPath)
|
|
99
|
+
if (!fs.existsSync(fullPath)) {
|
|
100
|
+
return { valid: false, missingExports: ["package.json not found"], extraExports: [] }
|
|
101
|
+
}
|
|
102
|
+
const pkg = JSON.parse(fs.readFileSync(fullPath, "utf8"))
|
|
103
|
+
const exportsMap = pkg.exports || {}
|
|
104
|
+
const sourceEntries = findSourceEntries(srcDir)
|
|
105
|
+
|
|
106
|
+
const expectedKeys = sourceEntries.map((file) => {
|
|
107
|
+
const rel = file.replace(new RegExp(`^${srcDir}/`), "").replace(/\.(ts|tsx|js|jsx)$/, "")
|
|
108
|
+
return rel === "index" ? "." : `./${rel}`
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const definedKeys = Object.keys(exportsMap)
|
|
112
|
+
const missingExports = expectedKeys.filter(
|
|
113
|
+
(k) => !definedKeys.includes(k) && !definedKeys.includes("./*")
|
|
114
|
+
)
|
|
115
|
+
const extraExports = definedKeys.filter(
|
|
116
|
+
(k) => k !== "." && k !== "./*" && !k.includes("*") && !expectedKeys.includes(k)
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
valid: missingExports.length === 0,
|
|
121
|
+
missingExports,
|
|
122
|
+
extraExports
|
|
123
|
+
}
|
|
124
|
+
} catch (err: any) {
|
|
125
|
+
return { valid: false, missingExports: [err.message], extraExports: [] }
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface RimelightPackOptions {
|
|
130
|
+
entry?: string[] | "auto"
|
|
131
|
+
autoEntry?: boolean | string
|
|
132
|
+
pack?: Record<string, any>
|
|
133
|
+
autoExternal?: boolean
|
|
134
|
+
[key: string]: any
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function rimelightPackConfig(options: RimelightPackOptions = {}): any {
|
|
138
|
+
const { entry, autoEntry, pack = {}, autoExternal = true, ...rest } = options
|
|
139
|
+
|
|
140
|
+
let resolvedEntry: string[] = ["src/index.ts"]
|
|
141
|
+
|
|
142
|
+
if (Array.isArray(entry)) {
|
|
143
|
+
resolvedEntry = entry
|
|
144
|
+
} else if (entry === "auto" || autoEntry) {
|
|
145
|
+
const dir = typeof autoEntry === "string" ? autoEntry : "src"
|
|
146
|
+
const discovered = findSourceEntries(dir)
|
|
147
|
+
if (discovered.length > 0) {
|
|
148
|
+
resolvedEntry = discovered
|
|
149
|
+
}
|
|
150
|
+
} else if (typeof entry === "string") {
|
|
151
|
+
resolvedEntry = [entry]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const discoveredExternals = autoExternal ? findPackageExternals() : []
|
|
155
|
+
const userExternal = pack["external"] || []
|
|
156
|
+
const userExternalList = Array.isArray(userExternal) ? userExternal : [userExternal]
|
|
157
|
+
const userNeverBundle = (pack["deps"] as Record<string, any> | undefined)?.["neverBundle"] || []
|
|
158
|
+
const userNeverBundleList = Array.isArray(userNeverBundle) ? userNeverBundle : [userNeverBundle]
|
|
159
|
+
const mergedExternal = Array.from(
|
|
160
|
+
new Set([...userExternalList, ...userNeverBundleList, ...discoveredExternals])
|
|
161
|
+
).filter(Boolean)
|
|
162
|
+
|
|
30
163
|
return {
|
|
31
164
|
...rimelightConfig(),
|
|
32
165
|
...rest,
|
|
33
166
|
pack: {
|
|
34
|
-
entry,
|
|
167
|
+
entry: resolvedEntry,
|
|
35
168
|
dts: true,
|
|
169
|
+
...(mergedExternal.length > 0 ? { deps: { neverBundle: mergedExternal } } : {}),
|
|
36
170
|
...pack
|
|
37
171
|
}
|
|
38
172
|
}
|