@poveste/plugin-vue 0.13.1 → 0.15.0
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 +1 -1
- package/dist/bundled/client/app/MountStory.js +3 -3
- package/dist/bundled/client/app/RenderStory.js +15 -9
- package/dist/bundled/client/app/Story.js +56 -43
- package/dist/bundled/client/app/Variant.js +32 -27
- package/dist/bundled/client/app/global-components.js +11 -10
- package/dist/bundled/client/app/host.js +2 -2
- package/dist/bundled/client/app/util.js +31 -26
- package/dist/bundled/client/client.js +4 -4
- package/dist/bundled/client/codegen.js +79 -60
- package/dist/bundled/client/server/Story.js +9 -7
- package/dist/bundled/client/server/Variant.js +1 -0
- package/dist/bundled/client/server/run.js +2 -2
- package/dist/client/app/MountStory.d.ts +3 -3
- package/dist/client/app/RenderStory.d.ts +1 -1
- package/dist/client/app/Story.d.ts +10 -7
- package/dist/client/app/Variant.d.ts +14 -13
- package/dist/client/app/render-context.d.ts +1 -1
- package/dist/client/app/util.d.ts +6 -3
- package/dist/client/codegen.d.ts +29 -0
- package/dist/client/server/Story.d.ts +17 -17
- package/dist/client/server/Variant.d.ts +10 -10
- package/dist/commands/generate-story.client.js +4 -4
- package/dist/commands/generate-story.server.js +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.node.js +2 -0
- package/dist/util/list-components.d.ts +1 -1
- package/dist/util/list-components.js +63 -6
- package/dist/util/list-components.spec.d.ts +1 -0
- package/dist/util/list-components.spec.js +46 -0
- package/package.json +12 -11
- package/src/client/__tests__/codegen-attrs.spec.ts +149 -0
- package/src/client/app/MountStory.ts +5 -1
- package/src/client/app/RenderStory.ts +6 -1
- package/src/client/app/RouterLinkStub.ts +1 -1
- package/src/client/app/Story.ts +78 -37
- package/src/client/app/Variant.ts +26 -23
- package/src/client/app/__tests__/preview-variants.spec.ts +76 -0
- package/src/client/app/auto-props.ts +2 -2
- package/src/client/app/global-components.ts +20 -14
- package/src/client/app/host.ts +9 -6
- package/src/client/app/util.ts +17 -7
- package/src/client/codegen.ts +81 -29
- package/src/client/server/Story.ts +10 -4
- package/src/client/server/Variant.ts +3 -0
- package/src/client/server/run.ts +5 -4
- package/src/commands/generate-story.client.ts +4 -4
- package/src/commands/generate-story.server.ts +2 -2
- package/src/helpers.ts +2 -2
- package/src/index.node.ts +2 -0
- package/src/util/list-components.spec.ts +54 -0
- package/src/util/list-components.ts +68 -6
package/src/client/server/run.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ServerRunPayload } from '@poveste/shared'
|
|
1
|
+
import type { ServerRunPayload, ServerStory } from '@poveste/shared'
|
|
2
2
|
import type { Vue3StorySetupApi, Vue3StorySetupHandler } from '../../helpers.js'
|
|
3
3
|
import { getSetupHook } from '@poveste/shared'
|
|
4
4
|
// @ts-expect-error virtual module id
|
|
@@ -15,7 +15,7 @@ export async function run({ file, storyData, el }: ServerRunPayload) {
|
|
|
15
15
|
|
|
16
16
|
const app = createApp({
|
|
17
17
|
provide: {
|
|
18
|
-
addStory(data) {
|
|
18
|
+
addStory(data: ServerStory) {
|
|
19
19
|
storyData.push(data)
|
|
20
20
|
},
|
|
21
21
|
hstStoryFile: file,
|
|
@@ -33,8 +33,9 @@ export async function run({ file, storyData, el }: ServerRunPayload) {
|
|
|
33
33
|
|
|
34
34
|
const setupApi: Vue3StorySetupApi = {
|
|
35
35
|
app,
|
|
36
|
-
story
|
|
37
|
-
|
|
36
|
+
// No story or variant exists while collecting.
|
|
37
|
+
story: undefined,
|
|
38
|
+
variant: undefined,
|
|
38
39
|
addWrapper: () => { /* noop */ },
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -16,13 +16,13 @@ export default {
|
|
|
16
16
|
label: 'File name',
|
|
17
17
|
type: 'text',
|
|
18
18
|
required: true,
|
|
19
|
-
defaultValue: answers => answers
|
|
19
|
+
defaultValue: answers => answers['component']?.replace(/[^/]+\/([^/]+)\.vue$/, '$1.story.vue'),
|
|
20
20
|
},
|
|
21
21
|
],
|
|
22
22
|
clientAction: (params) => {
|
|
23
|
-
const index = params
|
|
24
|
-
const dirname = params
|
|
25
|
-
const file = `${dirname}${params
|
|
23
|
+
const index = params['component'].lastIndexOf('/')
|
|
24
|
+
const dirname = params['component'].substring(0, index + 1)
|
|
25
|
+
const file = `${dirname}${params['fileName']}`
|
|
26
26
|
const storyId = kebabCase(file.toLowerCase())
|
|
27
27
|
openStory(storyId)
|
|
28
28
|
},
|
|
@@ -9,13 +9,13 @@ export default {
|
|
|
9
9
|
icon: 'https://vuejs.org/logo.svg',
|
|
10
10
|
searchText: 'generate create',
|
|
11
11
|
async serverAction(params) {
|
|
12
|
-
const targetFile = path.join(path.dirname(params
|
|
12
|
+
const targetFile = path.join(path.dirname(params['component']), params['fileName'])
|
|
13
13
|
|
|
14
14
|
if (fs.existsSync(targetFile)) {
|
|
15
15
|
throw new Error(`File ${targetFile} already exists`)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const { component, componentName, isTs } = await getComponentInfo(params
|
|
18
|
+
const { component, componentName, isTs } = await getComponentInfo(params['component'])
|
|
19
19
|
|
|
20
20
|
const content = `<script setup${isTs ? ' lang="ts"' : ''}>
|
|
21
21
|
import ${componentName} from './${component}'
|
package/src/helpers.ts
CHANGED
package/src/index.node.ts
CHANGED
|
@@ -32,6 +32,7 @@ export function HstVue(): Plugin {
|
|
|
32
32
|
if ((this.meta as any).poveste?.isCollecting && id.endsWith('.vue')) {
|
|
33
33
|
return `const _stubComponent = (name) => ['Story','Variant'].some(validName => name.toLowerCase() === validName.toLowerCase()) ? _resolveComponent(name) : ({ render: () => null });${code?.replaceAll('_resolveComponent(', '_stubComponent(') ?? ''}`
|
|
34
34
|
}
|
|
35
|
+
return undefined
|
|
35
36
|
},
|
|
36
37
|
},
|
|
37
38
|
],
|
|
@@ -57,6 +58,7 @@ export function HstVue(): Plugin {
|
|
|
57
58
|
return listComponentFiles(api.payload.search, api.getConfig().storyMatch)
|
|
58
59
|
}
|
|
59
60
|
}
|
|
61
|
+
return undefined
|
|
60
62
|
},
|
|
61
63
|
}
|
|
62
64
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { dirname, join } from 'node:path'
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
5
|
+
import { listComponentFiles } from './list-components.js'
|
|
6
|
+
|
|
7
|
+
const roots: string[] = []
|
|
8
|
+
|
|
9
|
+
function tree(files: Record<string, string>): string {
|
|
10
|
+
const root = mkdtempSync(join(tmpdir(), 'list-components-'))
|
|
11
|
+
roots.push(root)
|
|
12
|
+
for (const [path, content] of Object.entries(files)) {
|
|
13
|
+
mkdirSync(dirname(join(root, path)), { recursive: true })
|
|
14
|
+
writeFileSync(join(root, path), content)
|
|
15
|
+
}
|
|
16
|
+
return root
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
for (const root of roots.splice(0)) {
|
|
21
|
+
rmSync(root, { recursive: true, force: true })
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
// Listing honoured .gitignore through globby's `gitignore: true`, and tinyglobby
|
|
26
|
+
// has no such option, so the filtering is ours now (#839).
|
|
27
|
+
describe('listComponentFiles', () => {
|
|
28
|
+
it('leaves out components git ignores, from the root .gitignore and a nested one', async () => {
|
|
29
|
+
const root = tree({
|
|
30
|
+
'.git/HEAD': 'ref: refs/heads/main\n',
|
|
31
|
+
'.gitignore': 'generated/\n',
|
|
32
|
+
'app/.gitignore': 'scratch/*\n!scratch/Kept.vue\n',
|
|
33
|
+
'app/src/Button.vue': '',
|
|
34
|
+
'app/src/generated/Output.vue': '',
|
|
35
|
+
'app/scratch/Draft.vue': '',
|
|
36
|
+
'app/scratch/Kept.vue': '',
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const files = await listComponentFiles('', [], 10, join(root, 'app'))
|
|
40
|
+
|
|
41
|
+
expect(files.sort()).toEqual(['scratch/Kept.vue', 'src/Button.vue'])
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('still skips node_modules and the patterns it is given', async () => {
|
|
45
|
+
const root = tree({
|
|
46
|
+
'.git/HEAD': 'ref: refs/heads/main\n',
|
|
47
|
+
'src/Button.vue': '',
|
|
48
|
+
'src/Button.story.vue': '',
|
|
49
|
+
'node_modules/pkg/Dep.vue': '',
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
expect(await listComponentFiles('', ['**/*.story.vue'], 10, root)).toEqual(['src/Button.vue'])
|
|
53
|
+
})
|
|
54
|
+
})
|
|
@@ -1,13 +1,75 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { dirname, join, relative, resolve, sep } from 'node:path'
|
|
3
|
+
import ignore from 'ignore'
|
|
4
|
+
import { glob } from 'tinyglobby'
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
function toPosix(path: string): string {
|
|
7
|
+
return path.split(sep).join('/')
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Whether a file under `cwd` is git-ignored, the way globby's `gitignore: true`
|
|
12
|
+
* decided it: every `.gitignore` from the repository root down, each pattern
|
|
13
|
+
* relative to its own file. tinyglobby reads none of them (#839).
|
|
14
|
+
*/
|
|
15
|
+
async function gitIgnoredFilter(cwd: string): Promise<(file: string) => boolean> {
|
|
16
|
+
let root = cwd
|
|
17
|
+
while (!existsSync(join(root, '.git'))) {
|
|
18
|
+
const parent = dirname(root)
|
|
19
|
+
if (parent === root) {
|
|
20
|
+
root = cwd
|
|
21
|
+
break
|
|
22
|
+
}
|
|
23
|
+
root = parent
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const ancestors: string[] = []
|
|
27
|
+
for (let dir = cwd; dir !== root;) {
|
|
28
|
+
dir = dirname(dir)
|
|
29
|
+
ancestors.unshift(join(dir, '.gitignore'))
|
|
30
|
+
}
|
|
31
|
+
// Shallow files first, so a nested `.gitignore` can override its parent.
|
|
32
|
+
const nested = (await glob('**/.gitignore', { cwd, absolute: true, dot: true, ignore: ['**/node_modules/**', '**/.git/**'] }))
|
|
33
|
+
.sort((a, b) => a.split('/').length - b.split('/').length || a.localeCompare(b))
|
|
34
|
+
|
|
35
|
+
const rules = ignore()
|
|
36
|
+
for (const file of [...ancestors, ...nested]) {
|
|
37
|
+
if (!existsSync(file)) {
|
|
38
|
+
continue
|
|
39
|
+
}
|
|
40
|
+
const base = toPosix(relative(root, dirname(file)))
|
|
41
|
+
for (const raw of readFileSync(file, 'utf8').split(/\r?\n/)) {
|
|
42
|
+
const line = raw.trimEnd()
|
|
43
|
+
if (!line || line.startsWith('#')) {
|
|
44
|
+
continue
|
|
45
|
+
}
|
|
46
|
+
const negated = line.startsWith('!')
|
|
47
|
+
let pattern = negated ? line.slice(1) : line
|
|
48
|
+
if (base) {
|
|
49
|
+
// A pattern with a slash before its end is anchored to its own directory;
|
|
50
|
+
// one without matches at any depth below it.
|
|
51
|
+
const anchored = pattern.replace(/\/$/, '').includes('/')
|
|
52
|
+
pattern = anchored ? `${base}/${pattern.replace(/^\//, '')}` : `${base}/**/${pattern}`
|
|
53
|
+
}
|
|
54
|
+
rules.add(negated ? `!${pattern}` : pattern)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return (file) => {
|
|
59
|
+
const path = toPosix(relative(root, resolve(cwd, file)))
|
|
60
|
+
return !path.startsWith('..') && rules.ignores(path)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function listComponentFiles(search = '', ignoredPatterns: string[] = [], limit = 10, cwd = process.cwd()) {
|
|
65
|
+
const isIgnored = await gitIgnoredFilter(cwd)
|
|
66
|
+
let files = (await glob('**/*.vue', {
|
|
67
|
+
cwd,
|
|
6
68
|
ignore: [
|
|
7
69
|
'node_modules',
|
|
8
|
-
...
|
|
70
|
+
...ignoredPatterns,
|
|
9
71
|
],
|
|
10
|
-
})
|
|
72
|
+
})).filter(file => !isIgnored(file))
|
|
11
73
|
if (search) {
|
|
12
74
|
const searchText = search.toLowerCase()
|
|
13
75
|
files = files.filter(file => file.toLowerCase().includes(searchText))
|