diff --git a/.changeset/curvy-eggs-deliver.md b/.changeset/curvy-eggs-deliver.md
new file mode 100644
index 000000000..d911cc1ba
--- /dev/null
+++ b/.changeset/curvy-eggs-deliver.md
@@ -0,0 +1,5 @@
+---
+'vite-plugin-watch-and-run': patch
+---
+
+add absolutePath in second param of run as info
diff --git a/.changeset/pre.json b/.changeset/pre.json
new file mode 100644
index 000000000..adb854d68
--- /dev/null
+++ b/.changeset/pre.json
@@ -0,0 +1,16 @@
+{
+ "mode": "pre",
+ "tag": "next",
+ "initialVersions": {
+ "@kitql-old/all-in": "0.9.6",
+ "create-kitql": "0.0.2",
+ "eslint-config-kitql": "0.0.2",
+ "@kitql/handles": "0.1.3",
+ "@kitql/helpers": "0.8.4",
+ "vite-plugin-kit-routes": "0.1.0",
+ "vite-plugin-striper": "0.0.4",
+ "vite-plugin-watch-and-run": "1.4.3",
+ "website": "1.1.2"
+ },
+ "changesets": []
+}
diff --git a/.changeset/quiet-horses-drop.md b/.changeset/quiet-horses-drop.md
new file mode 100644
index 000000000..354d16be8
--- /dev/null
+++ b/.changeset/quiet-horses-drop.md
@@ -0,0 +1,5 @@
+---
+'vite-plugin-striper': patch
+---
+
+add log_warning_on_throw_is_not_a_class option
diff --git a/packages/vite-plugin-striper/package.json b/packages/vite-plugin-striper/package.json
index a33ed712f..62d3922d6 100644
--- a/packages/vite-plugin-striper/package.json
+++ b/packages/vite-plugin-striper/package.json
@@ -42,7 +42,8 @@
"dependencies": {
"@babel/parser": "^7.23.0",
"@kitql/helpers": "workspace:*",
- "recast": "^0.23.4"
+ "recast": "^0.23.4",
+ "vite-plugin-watch-and-run": "workspace:*"
},
"sideEffects": false,
"publishConfig": {
diff --git a/packages/vite-plugin-striper/src/lib/plugin.ts b/packages/vite-plugin-striper/src/lib/plugin.ts
index 5fd6523ca..5e024da9f 100644
--- a/packages/vite-plugin-striper/src/lib/plugin.ts
+++ b/packages/vite-plugin-striper/src/lib/plugin.ts
@@ -1,14 +1,27 @@
import { green, Log, yellow } from '@kitql/helpers'
+import { readFileSync } from 'node:fs'
import type { Plugin } from 'vite'
+import watch_and_run from 'vite-plugin-watch-and-run'
-import { transform } from './transform.js'
+import { transformDecorator } from './transformDecorator.js'
+import { transformWarningThrow, type WarningThrow } from './transformWarningThrow.js'
export type ViteStriperOptions = {
/**
* for example: `['BackendMethod']`
*/
- decorators: string[]
+ decorators?: string[]
+ /**
+ * If true, skip warnings if a throw is not a class.
+ *
+ * Default: `true`
+ */
+ log_warning_on_throw_is_not_a_class?: boolean
+
+ /**
+ * internal usage ;-)
+ */
debug?: boolean
}
@@ -30,34 +43,104 @@ export type ViteStriperOptions = {
* ```
*
*/
-export function striper(options: ViteStriperOptions): Plugin {
+export function striper(options?: ViteStriperOptions): Plugin[] {
const log = new Log('striper')
+ let listOrThrow: WarningThrow[] = []
+ const logWarningThrow =
+ options?.log_warning_on_throw_is_not_a_class === undefined ||
+ options?.log_warning_on_throw_is_not_a_class === true
- return {
- name: 'vite-plugin-striper',
- enforce: 'pre',
+ return [
+ {
+ name: 'vite-plugin-striper-decorator',
+ enforce: 'pre',
- transform: async (code, filepath, option) => {
- // Don't transform server-side code
- if (option?.ssr) {
- return
- }
- // files are only in ts
- if (!filepath.endsWith('.ts')) {
- return
- }
+ buildStart: () => {
+ listOrThrow = []
+ },
+
+ transform: async (code, filepath, option) => {
+ if (logWarningThrow) {
+ const prjPath = process.cwd()
+ // Only file in our project
+ if (filepath.startsWith(prjPath)) {
+ const { list } = await transformWarningThrow(filepath, code, logWarningThrow)
+ listOrThrow.push(
+ ...list.map(item => ({ ...item, pathFile: filepath.replace(prjPath, '') })),
+ )
+ }
+ }
- const { transformed, ...rest } = await transform(code, options.decorators ?? [])
+ // Don't transform server-side code
+ if (option?.ssr) {
+ return
+ }
+ // files are only in ts
+ if (!filepath.endsWith('.ts')) {
+ return
+ }
- if (options?.debug && transformed) {
- log.info(`
-${green('-----')} after transform of ${yellow(filepath)}
-${rest.code}
-${green('-----')}
-`)
- }
+ if (options && (options?.decorators ?? []).length > 0) {
+ const { transformed, ...rest } = await transformDecorator(code, options.decorators ?? [])
- return rest
+ if (options?.debug && transformed) {
+ log.info(
+ `` +
+ `${green('-----')} after transform of ${yellow(filepath)}` +
+ `${rest.code}` +
+ `${green('-----')}` +
+ ``,
+ )
+ }
+
+ return rest
+ }
+
+ return
+ },
+
+ buildEnd: async () => {
+ listOrThrow.forEach(item => {
+ log.error(
+ `Throw is not a new class in ${yellow(item.pathFile)}:${yellow(String(item.line))}`,
+ )
+ })
+ },
},
- }
+
+ // Run the thing when any change in a +page.svelte (add, remove, ...)
+ watch_and_run([
+ {
+ name: 'kit-routes-watch',
+ logs: [],
+ watch: ['**/*.ts'],
+ run: async (server, absolutePath) => {
+ if (logWarningThrow) {
+ const prjPath = process.cwd()
+
+ // Only file in our project
+ if (absolutePath && absolutePath.startsWith(prjPath)) {
+ const code = readFileSync(absolutePath, { encoding: 'utf8' })
+
+ const { list } = await transformWarningThrow(
+ absolutePath + '?' + new Date().toISOString(),
+ code,
+ logWarningThrow,
+ )
+ listOrThrow.push(
+ ...list.map(item => ({ ...item, pathFile: absolutePath.replace(prjPath, '') })),
+ )
+ listOrThrow.forEach(item => {
+ log.error(
+ `Throw is not a new class in ${yellow(item.pathFile)}:${yellow(
+ String(item.line),
+ )}`,
+ )
+ })
+ }
+ }
+ },
+ },
+ ]),
+ ]
}
diff --git a/packages/vite-plugin-striper/src/lib/transform.spec.ts b/packages/vite-plugin-striper/src/lib/transformDecorator.spec.ts
similarity index 76%
rename from packages/vite-plugin-striper/src/lib/transform.spec.ts
rename to packages/vite-plugin-striper/src/lib/transformDecorator.spec.ts
index 95cb0ae1f..166e85a00 100644
--- a/packages/vite-plugin-striper/src/lib/transform.spec.ts
+++ b/packages/vite-plugin-striper/src/lib/transformDecorator.spec.ts
@@ -1,9 +1,10 @@
-import { expect, it } from 'vitest'
+import { describe, expect, it } from 'vitest'
-import { transform } from './transform.js'
+import { transformDecorator } from './transformDecorator.js'
-it('should empty @BackendMethod and clean imports', async () => {
- const code = `import { Allow, BackendMethod, remult } from "remult";
+describe('decorator', () => {
+ it('should empty @BackendMethod and clean imports', async () => {
+ const code = `import { Allow, BackendMethod, remult } from "remult";
import { Task } from "./task";
import { AUTH_SECRET } from "$env/static/private";
@@ -34,9 +35,9 @@ export class TasksController {
}
`
- const transformed = await transform(code, ['BackendMethod'])
+ const transformed = await transformDecorator(code, ['BackendMethod'])
- expect(transformed).toMatchInlineSnapshot(`
+ expect(transformed).toMatchInlineSnapshot(`
{
"code": "import { Allow, BackendMethod } from \\"remult\\";
@@ -56,10 +57,10 @@ export class TasksController {
"transformed": true,
}
`)
-})
+ })
-it('should not crash if there is an error in the original file', async () => {
- const code = `import { Allow, BackendMethod, remult } from "remult";
+ it('should not crash if there is an error in the original file', async () => {
+ const code = `import { Allow, BackendMethod, remult } from "remult";
import { Task } from "./task";
import { AUTH_SECRET } from "$env/static/private";
@@ -71,9 +72,9 @@ export class TasksController {
}
`
- const transformed = await transform(code, ['BackendMethod'])
+ const transformed = await transformDecorator(code, ['BackendMethod'])
- expect(transformed).toMatchInlineSnapshot(`
+ expect(transformed).toMatchInlineSnapshot(`
{
"code": "import { Allow, BackendMethod, remult } from \\"remult\\";
import { Task } from \\"./task\\";
@@ -89,10 +90,10 @@ export class TasksController {
"transformed": false,
}
`)
-})
+ })
-it('should not do anything as there is no @BackendMethod', async () => {
- const code = `import { Allow, BackendMethod, remult } from "remult";
+ it('should not do anything as there is no @BackendMethod', async () => {
+ const code = `import { Allow, BackendMethod, remult } from "remult";
import { Task } from "./task";
import { AUTH_SECRET } from "$env/static/private";
@@ -112,9 +113,9 @@ export class TasksController {
}
`
- const transformed = await transform(code, ['BackendMethod'])
+ const transformed = await transformDecorator(code, ['BackendMethod'])
- expect(transformed).toMatchInlineSnapshot(`
+ expect(transformed).toMatchInlineSnapshot(`
{
"code": "import { Allow, BackendMethod, remult } from \\"remult\\";
import { Task } from \\"./task\\";
@@ -140,10 +141,10 @@ export class TasksController {
"transformed": false,
}
`)
-})
+ })
-it('should strip also unused methods', async () => {
- const code = `import { TOP_SECRET, TOP_SECRET_NOT_USED } from '$env/static/private';
+ it('should strip also unused methods', async () => {
+ const code = `import { TOP_SECRET, TOP_SECRET_NOT_USED } from '$env/static/private';
import { stry0 } from '@kitql/helper';
import { BackendMethod, Entity, Fields, remult } from 'remult';
@@ -171,9 +172,9 @@ it('should strip also unused methods', async () => {
}
`
- const transformed = await transform(code, ['BackendMethod'])
+ const transformed = await transformDecorator(code, ['BackendMethod'])
- expect(transformed).toMatchInlineSnapshot(`
+ expect(transformed).toMatchInlineSnapshot(`
{
"code": "import { BackendMethod, Entity, Fields } from \\"remult\\";
@@ -192,4 +193,5 @@ it('should strip also unused methods', async () => {
"transformed": true,
}
`)
+ })
})
diff --git a/packages/vite-plugin-striper/src/lib/transform.ts b/packages/vite-plugin-striper/src/lib/transformDecorator.ts
similarity index 97%
rename from packages/vite-plugin-striper/src/lib/transform.ts
rename to packages/vite-plugin-striper/src/lib/transformDecorator.ts
index f34aa8e2f..9db05c190 100644
--- a/packages/vite-plugin-striper/src/lib/transform.ts
+++ b/packages/vite-plugin-striper/src/lib/transformDecorator.ts
@@ -4,7 +4,7 @@ import { prettyPrint } from 'recast'
const { visit } = recast.types
-export const transform = async (code: string, decorators_to_strip: string[]) => {
+export const transformDecorator = async (code: string, decorators_to_strip: string[]) => {
try {
const codeParsed = parse(code ?? '', {
plugins: ['typescript', 'importAssertions', 'decorators-legacy'],
diff --git a/packages/vite-plugin-striper/src/lib/transformWarningThrow.spec.ts b/packages/vite-plugin-striper/src/lib/transformWarningThrow.spec.ts
new file mode 100644
index 000000000..8785e7c88
--- /dev/null
+++ b/packages/vite-plugin-striper/src/lib/transformWarningThrow.spec.ts
@@ -0,0 +1,45 @@
+import { describe, expect, it } from 'vitest'
+
+import { transformWarningThrow } from './transformWarningThrow.js'
+
+describe('warning on throw is not a class', () => {
+ it('should not warn', async () => {
+ const code = `import type { RequestHandler } from './$types'
+
+ export const GET: RequestHandler = async () => {
+ throw new Error('Not implemented')
+ return new Response()
+ }`
+
+ const transformed = await transformWarningThrow('myfile', code, true)
+
+ expect(transformed).toMatchInlineSnapshot(`
+ {
+ "list": [],
+ }
+ `)
+ })
+
+ it('should warn', async () => {
+ const code = `import type { RequestHandler } from './$types'
+
+ export const GET: RequestHandler = async () => {
+ throw 7
+ return new Response()
+ }
+ `
+
+ const transformed = await transformWarningThrow('myfile', code, true)
+
+ expect(transformed).toMatchInlineSnapshot(`
+ {
+ "list": [
+ {
+ "line": 4,
+ "pathFile": "myfile",
+ },
+ ],
+ }
+ `)
+ })
+})
diff --git a/packages/vite-plugin-striper/src/lib/transformWarningThrow.ts b/packages/vite-plugin-striper/src/lib/transformWarningThrow.ts
new file mode 100644
index 000000000..70e06c74d
--- /dev/null
+++ b/packages/vite-plugin-striper/src/lib/transformWarningThrow.ts
@@ -0,0 +1,47 @@
+import { parse } from '@babel/parser'
+import * as recast from 'recast'
+import { prettyPrint } from 'recast'
+
+const { visit } = recast.types
+
+export type WarningThrow = {
+ pathFile: string
+ line: number
+}
+
+export const transformWarningThrow = async (
+ pathFile: string,
+ code: string,
+ log_warning_on_throw_is_not_a_class: boolean,
+) => {
+ try {
+ const codeParsed = parse(code ?? '', {
+ plugins: ['typescript', 'importAssertions', 'decorators-legacy'],
+ sourceType: 'module',
+ }).program as recast.types.namedTypes.Program
+
+ let list: WarningThrow[] = []
+
+ visit(codeParsed, {
+ visitFunction(path) {
+ // Existing code for processing functions...
+ this.traverse(path)
+ },
+ visitThrowStatement(path) {
+ if (log_warning_on_throw_is_not_a_class) {
+ const thrownExpr = path.node.argument
+ // Check if thrownExpr is not a class
+ if (thrownExpr && thrownExpr.type !== 'NewExpression') {
+ list.push({ pathFile, line: path.node.loc?.start.line ?? 0 })
+ }
+ }
+ this.traverse(path)
+ },
+ })
+
+ return { list }
+ } catch (error) {
+ // if anything happens, just return the original code
+ return { list: [] }
+ }
+}
diff --git a/packages/vite-plugin-striper/src/routes/+page.svelte b/packages/vite-plugin-striper/src/routes/+page.svelte
index e965047ad..54964ccf9 100644
--- a/packages/vite-plugin-striper/src/routes/+page.svelte
+++ b/packages/vite-plugin-striper/src/routes/+page.svelte
@@ -1 +1,4 @@
Hello
+
+ThrowClass
+ThrowRandom
diff --git a/packages/vite-plugin-striper/src/routes/demoThrowClass/+server.ts b/packages/vite-plugin-striper/src/routes/demoThrowClass/+server.ts
new file mode 100644
index 000000000..206030381
--- /dev/null
+++ b/packages/vite-plugin-striper/src/routes/demoThrowClass/+server.ts
@@ -0,0 +1,6 @@
+import type { RequestHandler } from './$types'
+
+export const GET: RequestHandler = async () => {
+ throw new Error('Not implemented')
+ return new Response()
+}
diff --git a/packages/vite-plugin-striper/src/routes/demoThrowRandom/+server.ts b/packages/vite-plugin-striper/src/routes/demoThrowRandom/+server.ts
new file mode 100644
index 000000000..f4d16d54e
--- /dev/null
+++ b/packages/vite-plugin-striper/src/routes/demoThrowRandom/+server.ts
@@ -0,0 +1,6 @@
+// Here is the file?
+
+export const GET = async () => {
+ throw 7
+ return new Response()
+}
diff --git a/packages/vite-plugin-striper/vite.config.ts b/packages/vite-plugin-striper/vite.config.ts
index b4713153d..c01b7bb4c 100644
--- a/packages/vite-plugin-striper/vite.config.ts
+++ b/packages/vite-plugin-striper/vite.config.ts
@@ -4,7 +4,11 @@ import { defineConfig } from 'vite'
import { striper } from './src/lib/plugin.js'
export default defineConfig({
- plugins: [striper(), sveltekit()],
+ plugins: [
+ striper({ log_warning_on_throw_is_not_a_class: true }),
+ //
+ sveltekit(),
+ ],
test: {
include: ['src/**/*.{test,spec}.{js,ts}'],
},
diff --git a/packages/vite-plugin-watch-and-run/src/lib/index.ts b/packages/vite-plugin-watch-and-run/src/lib/index.ts
index d5b73ed7b..aaada3482 100644
--- a/packages/vite-plugin-watch-and-run/src/lib/index.ts
+++ b/packages/vite-plugin-watch-and-run/src/lib/index.ts
@@ -31,7 +31,7 @@ export type Options = {
/**
* run command (npm run gen for example!)
*/
- run: string | ((server: ViteDevServer) => void | Promise)
+ run: string | ((server: ViteDevServer, absolutePath: string | null) => void | Promise)
/**
* Delay before running the run command (in ms)
@@ -65,7 +65,7 @@ export type WatchKind = KindWithPath | KindWithoutPath
export type StateDetail = {
kind: WatchKind[]
logs: LogType[]
- run: string | ((server: ViteDevServer) => void | Promise)
+ run: string | ((server: ViteDevServer, absolutePath: string | null) => void | Promise)
delay: number
isRunning: boolean
watchFile?: (filepath: string) => boolean | Promise
@@ -179,7 +179,7 @@ async function watcher(
setTimeout(async () => {
// if the run value is a function, we just have to call it and we're done
if (typeof info.run === 'function') {
- const promise = info.run(server)
+ const promise = info.run(server, absolutePath)
try {
if (promise) {
await promise
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 08ae2cfbf..93a5b7a8e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -234,6 +234,9 @@ importers:
recast:
specifier: ^0.23.4
version: 0.23.4
+ vite-plugin-watch-and-run:
+ specifier: workspace:*
+ version: link:../vite-plugin-watch-and-run/dist
devDependencies:
'@sveltejs/adapter-auto':
specifier: 2.1.0