Skip to content

Commit fd3dcb3

Browse files
authored
Stripper++ (#931)
* renames * starting with imports * start to look good! * okay imports * init usage * structure and ssred suff preparation * tmp * This is the next level * tests structure improvements * pnpm in root * format * format * adding more tests * doc & lint * linting
1 parent 7e38b22 commit fd3dcb3

27 files changed

+1822
-85
lines changed

.changeset/wide-waves-read.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
'vite-plugin-stripper': minor
3+
---
4+
5+
You should STOP using `decorators` and `hard` in favor of using the new `strip` config!
6+
```ts
7+
strip: [
8+
{ decorator: 'BackendMethod' },
9+
{
10+
decorator: 'Entity',
11+
args_1: [
12+
{ fn: 'backendPrefilter' },
13+
{ fn: 'backendPreprocessFilter' },
14+
{ fn: 'sqlExpression' },
15+
// {
16+
// fn: 'saved',
17+
// excludeEntityKeys: ['users']
18+
// }
19+
]
20+
}
21+
]
22+
```

docs/src/content/docs/docs/tools/07_vite-plugin-stripper.mdx

+21-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { stripper } from 'vite-plugin-stripper'
2323
export default defineConfig({
2424
plugins: [
2525
// To strip `@BackendMethod` from your browser bundle
26-
stripper({ decorators: ['BackendMethod'] }),
26+
stripper({ strip: ['BackendMethod'] }),
2727
sveltekit(),
2828
],
2929
})
@@ -35,6 +35,24 @@ export default defineConfig({
3535
npm i -D vite-plugin-stripper
3636
```
3737

38-
## Configuration
38+
## Advanced configuration
3939

40-
🚧🚧🚧
40+
```ts
41+
stripper({
42+
strip: [
43+
{ decorator: 'BackendMethod' },
44+
{
45+
decorator: 'Entity',
46+
args_1: [
47+
{ fn: 'backendPrefilter' },
48+
{ fn: 'backendPreprocessFilter' },
49+
{ fn: 'sqlExpression' },
50+
// {
51+
// fn: 'saved',
52+
// excludeEntityKeys: ['users']
53+
// }
54+
],
55+
},
56+
],
57+
})
58+
```

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"@changesets/cli": "catalog:lib-author-helper",
1818
"@vitest/coverage-v8": "catalog:testing",
1919
"esbuild": "catalog:tooling",
20+
"prettier": "catalog:linting",
2021
"rimraf": "catalog:tooling"
2122
},
2223
"pnpm": {

packages/eslint-config/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
"lint:example": "kitql-lint",
3535
"inspector": "npx @eslint/config-inspector"
3636
},
37+
"peerDependencies": {
38+
"prettier": "catalog:linting"
39+
},
3740
"dependencies": {
3841
"@eslint/compat": "catalog:linting",
3942
"@eslint/js": "catalog:linting",

packages/helpers/eslint.config.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import kitql from '@kitql/eslint-config'
1+
import { kitql } from '@kitql/eslint-config'
22

3-
export default [...kitql]
3+
export default [...kitql()]
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
db/

packages/vite-plugin-stripper/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"@sveltejs/kit": "catalog:sveltekit",
3535
"@sveltejs/package": "catalog:sveltekit",
3636
"@sveltejs/vite-plugin-svelte": "catalog:sveltekit",
37+
"@vitest/ui": "catalog:",
3738
"publint": "catalog:lib-author-helper",
3839
"remult": "catalog:remult",
3940
"svelte": "catalog:svelte",
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { sequence } from '@sveltejs/kit/hooks'
22

3-
import { handleRemult } from './hooks/handleRemult.js'
3+
import { api as handleRemult } from './server/api.js'
44

55
export const handle = sequence(handleRemult)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import { describe, expect, it } from 'vitest'
2+
3+
import { imports, usage } from './ast.js'
4+
5+
describe('imports', () => {
6+
it('should return an import a', () => {
7+
const data = imports('import { a } from "lib"')
8+
expect(data.importsList).toMatchInlineSnapshot(`
9+
[
10+
{
11+
"localName": undefined,
12+
"name": "a",
13+
"source": "lib",
14+
"type": "named",
15+
},
16+
]
17+
`)
18+
})
19+
20+
it('should return an import a and b', () => {
21+
const data = imports('import { a, b } from "lib"')
22+
expect(data.importsList).toMatchInlineSnapshot(`
23+
[
24+
{
25+
"localName": undefined,
26+
"name": "a",
27+
"source": "lib",
28+
"type": "named",
29+
},
30+
{
31+
"localName": undefined,
32+
"name": "b",
33+
"source": "lib",
34+
"type": "named",
35+
},
36+
]
37+
`)
38+
})
39+
40+
it('should return an import a and b and c as d', () => {
41+
const data = imports('import { a, b, c as d } from "lib"')
42+
expect(data.importsList).toMatchInlineSnapshot(`
43+
[
44+
{
45+
"localName": undefined,
46+
"name": "a",
47+
"source": "lib",
48+
"type": "named",
49+
},
50+
{
51+
"localName": undefined,
52+
"name": "b",
53+
"source": "lib",
54+
"type": "named",
55+
},
56+
{
57+
"localName": "d",
58+
"name": "c",
59+
"source": "lib",
60+
"type": "named",
61+
},
62+
]
63+
`)
64+
})
65+
66+
it('should return an import a and type b', () => {
67+
const data = imports('import { a, type b } from "lib"')
68+
expect(data.importsList).toMatchInlineSnapshot(`
69+
[
70+
{
71+
"localName": undefined,
72+
"name": "a",
73+
"source": "lib",
74+
"type": "named",
75+
},
76+
{
77+
"localName": undefined,
78+
"name": "b",
79+
"source": "lib",
80+
"type": "type",
81+
},
82+
]
83+
`)
84+
})
85+
86+
it('should return an import types a and b', () => {
87+
const data = imports('import type { a, b } from "lib"')
88+
expect(data.importsList).toMatchInlineSnapshot(`
89+
[
90+
{
91+
"localName": undefined,
92+
"name": "a",
93+
"source": "lib",
94+
"type": "type",
95+
},
96+
{
97+
"localName": undefined,
98+
"name": "b",
99+
"source": "lib",
100+
"type": "type",
101+
},
102+
]
103+
`)
104+
})
105+
106+
it('should return * stuff as toto', () => {
107+
const data = imports('import * as toto from "lib"')
108+
expect(data.importsList).toMatchInlineSnapshot(`
109+
[
110+
{
111+
"name": "toto",
112+
"source": "lib",
113+
"type": "namespace",
114+
},
115+
]
116+
`)
117+
})
118+
119+
it('should handle bare imports', () => {
120+
const data = imports('import "lib"')
121+
expect(data.importsList).toMatchInlineSnapshot(`
122+
[
123+
{
124+
"name": "default",
125+
"source": "lib",
126+
"type": "default",
127+
},
128+
]
129+
`)
130+
})
131+
132+
it('should handle named imports', () => {
133+
const data = imports(`import { default as Icon } from './ui/Icon.svelte'`)
134+
expect(data.importsList).toMatchInlineSnapshot(`
135+
[
136+
{
137+
"localName": "Icon",
138+
"name": "default",
139+
"source": "./ui/Icon.svelte",
140+
"type": "named",
141+
},
142+
]
143+
`)
144+
})
145+
146+
it('should handle default imports', () => {
147+
const data = imports('import DefaultExport from "lib"')
148+
expect(data.importsList).toMatchInlineSnapshot(`
149+
[
150+
{
151+
"name": "DefaultExport",
152+
"source": "lib",
153+
"type": "default",
154+
},
155+
]
156+
`)
157+
})
158+
})
159+
160+
describe('usage', () => {
161+
it('should return an usage', () => {
162+
const code = `import { a } from "lib"
163+
const b = a`
164+
165+
const importsData = imports(code)
166+
const usageData = usage(code, importsData.importsList)
167+
168+
expect(usageData.importsList).toMatchInlineSnapshot(`[]`)
169+
})
170+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { parseTs, visit } from '@kitql/internals'
2+
3+
export type ImportInfo = {
4+
name: string
5+
type: 'default' | 'namespace' | 'named' | 'type'
6+
localName?: string
7+
source: string
8+
}
9+
10+
export type UserInfo = {
11+
used: boolean
12+
}
13+
14+
export const imports = (
15+
code_or_program: string | ReturnType<typeof parseTs>,
16+
): { program: ReturnType<typeof parseTs>; importsList: ImportInfo[] } => {
17+
const program = typeof code_or_program === 'string' ? parseTs(code_or_program) : code_or_program
18+
const importsList: ImportInfo[] = []
19+
20+
visit(program, {
21+
visitImportDeclaration(path: any) {
22+
const source = path.node.source.value as string
23+
const isTypeOnly = path.node.importKind === 'type'
24+
25+
// Handle bare imports (import "source")
26+
if (!path.node.specifiers || path.node.specifiers.length === 0) {
27+
importsList.push({
28+
name: 'default',
29+
type: 'default',
30+
source,
31+
})
32+
return false
33+
}
34+
35+
// Process all specifiers in this import declaration
36+
path.node.specifiers?.forEach((specifier: any) => {
37+
if (specifier.type === 'ImportDefaultSpecifier') {
38+
// Default import: import Name from 'source'
39+
importsList.push({
40+
name: specifier.local.name,
41+
type: 'default',
42+
source,
43+
})
44+
} else if (specifier.type === 'ImportNamespaceSpecifier') {
45+
// Namespace import: import * as Name from 'source'
46+
importsList.push({
47+
name: specifier.local.name,
48+
type: 'namespace',
49+
source,
50+
})
51+
} else if (specifier.type === 'ImportSpecifier') {
52+
// Named import: import { name } from 'source'
53+
// or type import: import type { name } from 'source'
54+
const importedName = specifier.imported?.name || specifier.local.name
55+
const localName = specifier.local.name
56+
57+
// Handle type imports
58+
const importType = isTypeOnly || specifier.importKind === 'type' ? 'type' : 'named'
59+
60+
importsList.push({
61+
name: importedName,
62+
type: importType,
63+
localName: importedName !== localName ? localName : undefined,
64+
source,
65+
})
66+
}
67+
})
68+
69+
return false
70+
},
71+
})
72+
73+
return { program, importsList }
74+
}
75+
76+
export const usage = (
77+
code_or_program: string | ReturnType<typeof parseTs>,
78+
importsList: ImportInfo[],
79+
): { program: ReturnType<typeof parseTs>; importsList: ImportInfo[] } => {
80+
const program = typeof code_or_program === 'string' ? parseTs(code_or_program) : code_or_program
81+
if (importsList.length === 0) return { program, importsList: [] }
82+
83+
const usageList: (ImportInfo & UserInfo)[] = []
84+
85+
return { program, importsList: [] }
86+
}

0 commit comments

Comments
 (0)