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/curvy-eggs-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'vite-plugin-watch-and-run': patch
---

add absolutePath in second param of run as info
16 changes: 16 additions & 0 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
@@ -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": []
}
5 changes: 5 additions & 0 deletions .changeset/quiet-horses-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'vite-plugin-striper': patch
---

add log_warning_on_throw_is_not_a_class option
3 changes: 2 additions & 1 deletion packages/vite-plugin-striper/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
133 changes: 108 additions & 25 deletions packages/vite-plugin-striper/src/lib/plugin.ts
Original file line number Diff line number Diff line change
@@ -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
}

Expand All @@ -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),
)}`,
)
})
}
}
},
},
]),
]
}
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -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\\";

Expand All @@ -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";

Expand All @@ -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\\";
Expand All @@ -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";

Expand All @@ -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\\";
Expand All @@ -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';

Expand Down Expand Up @@ -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\\";

Expand All @@ -192,4 +193,5 @@ it('should strip also unused methods', async () => {
"transformed": true,
}
`)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand Down
45 changes: 45 additions & 0 deletions packages/vite-plugin-striper/src/lib/transformWarningThrow.spec.ts
Original file line number Diff line number Diff line change
@@ -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",
},
],
}
`)
})
})
Loading