Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eleven-lies-behave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'vite-plugin-watch-and-run': patch
---

watch can look at an array of globs now
5 changes: 5 additions & 0 deletions .changeset/polite-ghosts-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'vite-plugin-kit-routes': patch
---

init plugin
3 changes: 3 additions & 0 deletions packages/vite-plugin-kit-routes/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
extends: ['eslint-config-kitql'],
}
11 changes: 11 additions & 0 deletions packages/vite-plugin-kit-routes/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.DS_Store
node_modules
/build
/dist
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
1 change: 1 addition & 0 deletions packages/vite-plugin-kit-routes/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
engine-strict=true
1 change: 1 addition & 0 deletions packages/vite-plugin-kit-routes/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# vite-plugin-kit-routes
5 changes: 5 additions & 0 deletions packages/vite-plugin-kit-routes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# ⚡vite-plugin-watch-and-run

_Part of [KitQL](https://github.com/jycouet/kitql#kitql), a set of tools helping **you** building efficient apps in a fast way._

### 👉 Check the [⚡Doc⚡](https://kitql.dev/docs/tools/06_vite-plugin-kit-routes)
65 changes: 65 additions & 0 deletions packages/vite-plugin-kit-routes/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"name": "vite-plugin-kit-routes",
"description": "vite-plugin that will help you maintain your routes in a single file",
"keywords": [
"vite"
],
"version": "0.0.1",
"license": "MIT",
"type": "module",
"repository": {
"type": "git",
"url": "https://github.com/jycouet/kitql",
"directory": "packages/vite-plugin-kit-routes",
"homepage": "https://github.com/jycouet/kitql/tree/main/packages/vite-plugin-kit-routes#readme"
},
"scripts": {
"prepare": "svelte-kit sync",
"dev": "vite dev",
"build": "vite build && svelte-package && node ../../scripts/package.js",
"preview": "vite preview",
"package": "svelte-package && publint",
"check": "svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"test": "vitest",
"test:ci": "vitest --coverage",
"lint": "kitql-lint",
"format": "kitql-lint --fix"
},
"devDependencies": {
"eslint-config-kitql": "workspace:*",
"@sveltejs/adapter-auto": "2.1.0",
"@sveltejs/kit": "1.25.2",
"@sveltejs/package": "2.2.2",
"publint": "0.2.4",
"svelte": "4.2.1",
"svelte-check": "3.5.2",
"tslib": "2.6.2",
"typescript": "5.2.2",
"vite": "4.4.2",
"vitest": "0.34.6"
},
"dependencies": {
"@kitql/helpers": "workspace:*",
"vite-plugin-watch-and-run": "workspace:*"
},
"sideEffects": false,
"publishConfig": {
"directory": "dist",
"access": "public"
},
"files": [
"dist",
"!dist/**/*.test.*",
"!dist/**/*.spec.*"
],
"svelte": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js",
"svelte": "./dist/index.js"
}
}
}
12 changes: 12 additions & 0 deletions packages/vite-plugin-kit-routes/src/app.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface Platform {}
}
}

export {}
12 changes: 12 additions & 0 deletions packages/vite-plugin-kit-routes/src/app.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div>%sveltekit.body%</div>
</body>
</html>
30 changes: 30 additions & 0 deletions packages/vite-plugin-kit-routes/src/lib/ROUTES.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export const PAGES = {
'/': (sp?: Record<string, string>) => {
return `/${appendSp(sp)}`
},
'/site/[id]': (id: string, sp?: Record<string, string>) => {
return `/site/${id}${appendSp(sp)}`
},
'/site/[param]/[yop]': (param: string, yop: string, sp?: Record<string, string>) => {
return `/site/${param}/${yop}${appendSp(sp)}`
},
}

// TODO: SERVERS methods?
export const SERVERS = {
'/site/[id]/one': (id: string, sp?: Record<string, string>) => {
return `/site/${id}/one${appendSp(sp)}`
},
}

// TODO: name actions
export const ACTIONS = {
'/site/[id]/two/[hello]': (id: string, hello: string) => {
return `/site/${id}/two/${hello}`
},
}

const appendSp = (sp?: Record<string, string>) => {
if (sp === undefined) return ''
return `?${new URLSearchParams(sp || {}).toString()}`
}
26 changes: 26 additions & 0 deletions packages/vite-plugin-kit-routes/src/lib/fs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import { dirname, join } from 'node:path'

export function read(pathFile: string) {
return readFileSync(pathFile, { encoding: 'utf8' })
}

export function write(pathFile: string, data: string[]) {
const fullDataToWrite = Array.isArray(data) ? data.join('\n') : data
createFolderIfNotExists(dirname(pathFile))
// Don't write if nothing changed!
if (existsSync(pathFile)) {
const currentFileData = read(pathFile)
if (fullDataToWrite === currentFileData) {
return false
}
}
writeFileSync(join(pathFile), fullDataToWrite)
return true
}

function createFolderIfNotExists(dir: string) {
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true })
}
}
150 changes: 150 additions & 0 deletions packages/vite-plugin-kit-routes/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { readdirSync } from 'fs'
import { spawn } from 'node:child_process'
import { green, Log, yellow } from '@kitql/helpers'
import type { Plugin } from 'vite'
import watch_and_run from 'vite-plugin-watch-and-run'
import { write } from './fs.js'

export type Options = {
/**
* run command after file updated
*
* @example
* ```ts
* 'npm exec prettier ./src/lib/ROUTES.ts -- -w'
* ```
*/
post_update_run?: string

/**
* @default 'src/lib/ROUTES.ts'
*/
generated_file_path?: string
}

function generated_file_path(params?: Options) {
return params?.generated_file_path ?? 'src/lib/ROUTES.ts'
}

// const routes_path = 'src/lib/ROUTES.ts'
const log = new Log('Kit Routes')

const getFiles = (dirPath: string, lookFor: '+page.svelte' | '+page.server.ts' | '+server.ts') => {
const files = readdirSync(dirPath, { recursive: true }) as string[]
return files
.filter(file => file.endsWith(lookFor))
.map(file => `/` + file.replace(`/${lookFor}`, '').replace(lookFor, ''))
}

export function extractParamsFromPath(path: string): string[] {
// Use a regular expression to match parameter placeholders like '[param]'
const paramPattern = /\[([^\]]+)]/g
const params = []

let match
while ((match = paramPattern.exec(path)) !== null) {
// The matched parameter name is in the first capturing group
params.push(match[1])
}

return params
}

const run = (params?: Options) => {
const files_pages = getFiles(`${process.cwd()}/src/routes`, '+page.svelte')
const files_server_pages = getFiles(`${process.cwd()}/src/routes`, '+page.server.ts')
const files_server = getFiles(`${process.cwd()}/src/routes`, '+server.ts')

const result = write(generated_file_path(params), [
`export const PAGES = {
${files_pages
.map(file_path => {
const params = extractParamsFromPath(file_path).map(c => `${c}: string`)
params.push(`sp?: Record<string, string>`)
return (
`"${file_path}": (${params.join(', ')}) => ` +
`{ return \`${file_path.replaceAll('[', '${').replaceAll(']', '}')}\${appendSp(sp)}\` }`
)
})
.join(',\n ')}
}

// TODO: SERVERS methods?
export const SERVERS = {
${files_server
.map(file_path => {
const params = extractParamsFromPath(file_path).map(c => `${c}: string`)
params.push(`sp?: Record<string, string>`)
return (
`"${file_path}": (${params.join(', ')}) => ` +
`{ return \`${file_path.replaceAll('[', '${').replaceAll(']', '}')}\${appendSp(sp)}\` }`
)
})
.join(',\n ')}
}

// TODO: name actions
export const ACTIONS = {
${files_server_pages
.map(file_path => {
const params = extractParamsFromPath(file_path).map(c => `${c}: string`)
return (
`"${file_path}": (${params.join(', ')}) => ` +
`{ return \`${file_path.replaceAll('[', '${').replaceAll(']', '}')}\` }`
)
})
.join(',\n ')}
}

const appendSp = (sp?: Record<string, string>) => {
if (sp === undefined) return ''
return \`?\${new URLSearchParams(sp || {}).toString()}\`
}
`,
])

// TODO: optimize this later. We want to write the new file only if different after prettier?! (having a tmp file somewhere?)
if (params?.post_update_run) {
log.info(`${yellow(`post_update_run`)} "${green(params?.post_update_run)}" running...`)
const child = spawn(params.post_update_run, { shell: true })
child.stdout.on('data', data => {
if (data.toString()) {
log.info(data.toString())
}
})
child.stderr.on('data', data => {
log.error(data.toString())
})
child.on('close', code => {
if (result) {
log.success(`${yellow(generated_file_path(params))} updated`)
}
})
} else {
if (result) {
log.success(`${yellow(generated_file_path(params))} updated`)
}
}
}

export function kitRoutes(params?: Options): Plugin[] {
return [
// Run the thing at startup
{
name: 'kit-routes',
configureServer() {
run(params)
},
},

// Run the thing when any change in a +page.svelte (add, remove, ...)
watch_and_run([
{
name: 'kit-routes-watch',
logs: [],
watch: ['**/+page.svelte', '**/+page.server.ts', '**/+server.ts'],
run: () => run(params),
},
]),
]
}
31 changes: 31 additions & 0 deletions packages/vite-plugin-kit-routes/src/lib/plugins.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { describe, expect, it } from 'vitest'
import { extractParamsFromPath } from './index.js'

describe('vite-plugin-kit-routes', () => {
it('get id', async () => {
expect(extractParamsFromPath('/site/[id]')).toMatchInlineSnapshot(`
[
"id",
]
`)
})

it('get params & id', async () => {
expect(extractParamsFromPath('/site/[param]/[id]')).toMatchInlineSnapshot(`
[
"param",
"id",
]
`)
})

it('get params & id', async () => {
expect(extractParamsFromPath('/[param]site/[yop](group)/[id]')).toMatchInlineSnapshot(`
[
"param",
"yop",
"id",
]
`)
})
})
20 changes: 20 additions & 0 deletions packages/vite-plugin-kit-routes/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script lang="ts">
import { PAGES } from '$lib/ROUTES.js'
</script>

<svelte:head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2/out/dark.css" />
</svelte:head>

<h1>vite-plugin-kit-routes</h1>

<hr />

<ul>
<a href={PAGES['/']()}>Home</a>
<a href={PAGES['/site/[param]/[yop]']('param', 'yop', { limit: '2' })}>Another route</a>
</ul>

<hr />

<slot />
1 change: 1 addition & 0 deletions packages/vite-plugin-kit-routes/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h2>Home</h2>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h2>site [id]</h2>
Loading