@vibecuting/component-project-helper 0.1.15 → 0.1.17
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/bin/component-project-helper.mjs +3 -3
- package/package.json +4 -3
- package/scripts/package-json.mjs +1 -1
- package/scripts/update-component-meta.mjs +60 -0
- package/src/decorators/index.test.ts +23 -0
- package/src/decorators/index.ts +95 -19
- package/src/discovery/index.test.ts +86 -159
- package/src/discovery/index.ts +646 -102
- package/src/index.ts +49 -10
- package/src/meta/generate-video-resource-meta.ts +198 -0
- package/src/meta/update-component-meta.test.ts +64 -0
- package/src/meta/update-component-meta.ts +47 -0
- package/src/resources/resource-descriptors.ts +47 -0
- package/src/resources/video-resource-descriptors.json +17 -0
- package/src/resources/video-resource.ts +143 -0
- package/src/schemas/index.ts +24 -2
- package/scripts/postinstall.mjs +0 -112
- package/scripts/preuninstall.mjs +0 -45
- package/scripts/render-markdown.mjs +0 -36
- package/src/lifecycle/package-json.ts +0 -63
- package/src/lifecycle/postinstall.test.ts +0 -114
- package/src/lifecycle/postinstall.ts +0 -127
- package/src/lifecycle/preuninstall.ts +0 -54
- package/src/markdown/index.test.ts +0 -20
- package/src/markdown/index.ts +0 -43
|
@@ -5,10 +5,10 @@ import path from 'node:path'
|
|
|
5
5
|
import { fileURLToPath } from 'node:url'
|
|
6
6
|
|
|
7
7
|
const binDir = path.dirname(fileURLToPath(import.meta.url))
|
|
8
|
-
const
|
|
9
|
-
const scriptPath = path.resolve(binDir, '../scripts',
|
|
8
|
+
const checkOnly = process.argv.includes('--check')
|
|
9
|
+
const scriptPath = path.resolve(binDir, '../scripts', 'update-component-meta.mjs')
|
|
10
10
|
|
|
11
|
-
const result = spawnSync(process.execPath, [scriptPath], {
|
|
11
|
+
const result = spawnSync(process.execPath, checkOnly ? [scriptPath, '--check'] : [scriptPath], {
|
|
12
12
|
stdio: 'inherit',
|
|
13
13
|
env: process.env,
|
|
14
14
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibecuting/component-project-helper",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
23
|
+
"update-component-meta": "node ./scripts/update-component-meta.mjs",
|
|
24
|
+
"update-component-skills": "pnpm run update-component-meta",
|
|
25
25
|
"lint": "node ../../../scripts/run-eslint.mjs .",
|
|
26
26
|
"typecheck": "node ../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsc -p tsconfig.json --noEmit",
|
|
27
27
|
"test": "node ../../../node_modules/vitest/vitest.mjs run"
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"reflect-metadata": "^0.2.2",
|
|
31
31
|
"typescript": "^5.9.3",
|
|
32
|
+
"tsx": "^4.19.2",
|
|
32
33
|
"zod": "4.1.12"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
package/scripts/package-json.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import path from 'node:path'
|
|
|
3
3
|
|
|
4
4
|
export const componentProjectSkillsScriptName = 'update-component-skills'
|
|
5
5
|
export const componentProjectSkillsScriptCommand =
|
|
6
|
-
'node ./node_modules/@vibecuting/component-project-helper/scripts/
|
|
6
|
+
'node ./node_modules/@vibecuting/component-project-helper/scripts/update-component-meta.mjs'
|
|
7
7
|
|
|
8
8
|
async function readPackageJson(projectRoot) {
|
|
9
9
|
const packageJsonPath = path.join(projectRoot, 'package.json')
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
|
|
9
|
+
function resolveLoaderPath() {
|
|
10
|
+
const candidates = [
|
|
11
|
+
path.resolve(process.cwd(), "node_modules/tsx/dist/loader.mjs"),
|
|
12
|
+
path.resolve(
|
|
13
|
+
process.cwd(),
|
|
14
|
+
"../../../project-templates/video-project/node_modules/tsx/dist/loader.mjs",
|
|
15
|
+
),
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
for (const candidate of candidates) {
|
|
19
|
+
if (existsSync(candidate)) {
|
|
20
|
+
return candidate;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return require.resolve("tsx");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const scriptPath = path.relative(process.cwd(), fileURLToPath(import.meta.url));
|
|
28
|
+
|
|
29
|
+
if (!process.env.COMPONENT_PROJECT_HELPER_UPDATE_COMPONENT_META_LOADER) {
|
|
30
|
+
const loaderPath = resolveLoaderPath();
|
|
31
|
+
const result = spawnSync(
|
|
32
|
+
process.execPath,
|
|
33
|
+
["--import", loaderPath, scriptPath, ...process.argv.slice(2)],
|
|
34
|
+
{
|
|
35
|
+
cwd: process.cwd(),
|
|
36
|
+
env: {
|
|
37
|
+
...process.env,
|
|
38
|
+
COMPONENT_PROJECT_HELPER_UPDATE_COMPONENT_META_LOADER: "1",
|
|
39
|
+
},
|
|
40
|
+
stdio: "inherit",
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
if (result.error) {
|
|
45
|
+
throw result.error;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
process.exit(result.status ?? 1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const helperModule = await import(
|
|
52
|
+
pathToFileURL(
|
|
53
|
+
path.resolve(process.cwd(), "src/meta/update-component-meta.ts"),
|
|
54
|
+
).href
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
await helperModule.updateComponentMeta(
|
|
58
|
+
process.cwd(),
|
|
59
|
+
process.argv.includes("--check"),
|
|
60
|
+
);
|
|
@@ -43,3 +43,26 @@ test('attaches normalized metadata to decorated function components', () => {
|
|
|
43
43
|
expect(decorated).toBe(SceneTitle)
|
|
44
44
|
expect(getComponentProjectComponentMetadata(SceneTitle)).toEqual(metadata)
|
|
45
45
|
})
|
|
46
|
+
|
|
47
|
+
test('attaches metadata to components with required props', () => {
|
|
48
|
+
type RequiredProps = {
|
|
49
|
+
title: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const metadata = defineComponentProjectComponentMetadata({
|
|
53
|
+
name: 'RequiredPropsScene',
|
|
54
|
+
description: 'Exercises required props support',
|
|
55
|
+
sourceFile: 'src/components/RequiredPropsScene.tsx',
|
|
56
|
+
aspectRatio: '16:9',
|
|
57
|
+
sceneType: 'scene',
|
|
58
|
+
tags: ['required', 'props'],
|
|
59
|
+
propsTypeName: 'RequiredProps',
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const RequiredPropsScene = (_props: RequiredProps) => null
|
|
63
|
+
|
|
64
|
+
const decorated = VideoComponent(metadata)(RequiredPropsScene)
|
|
65
|
+
|
|
66
|
+
expect(decorated).toBe(RequiredPropsScene)
|
|
67
|
+
expect(getComponentProjectComponentMetadata(RequiredPropsScene)).toEqual(metadata)
|
|
68
|
+
})
|
package/src/decorators/index.ts
CHANGED
|
@@ -1,40 +1,116 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type {
|
|
2
|
+
ScenePluginMetadata,
|
|
3
|
+
ThemePluginMetadata,
|
|
4
|
+
TransitionPluginMetadata,
|
|
5
|
+
VideoResourceMetadata,
|
|
6
|
+
} from '../resources/video-resource'
|
|
7
|
+
import {
|
|
8
|
+
VIDEO_RESOURCE_METADATA_KEY,
|
|
9
|
+
createVideoResourceAnnotation,
|
|
10
|
+
defineScenePluginMetadata as defineScenePluginMetadataBase,
|
|
11
|
+
defineThemePluginMetadata as defineThemePluginMetadataBase,
|
|
12
|
+
defineTransitionPluginMetadata as defineTransitionPluginMetadataBase,
|
|
13
|
+
getVideoResourceMetadata,
|
|
14
|
+
ScenePluginMetadataSchema,
|
|
15
|
+
type VideoResourceDescriptor,
|
|
16
|
+
} from '../resources/video-resource'
|
|
17
|
+
import {
|
|
18
|
+
sceneResourceDescriptor,
|
|
19
|
+
themeResourceDescriptor,
|
|
20
|
+
transitionResourceDescriptor,
|
|
21
|
+
} from '../resources/resource-descriptors'
|
|
5
22
|
import {
|
|
6
23
|
ComponentProjectComponentMetadataSchema,
|
|
7
|
-
type ComponentProjectComponentMetadata,
|
|
24
|
+
type ComponentProjectComponentMetadata as LegacyComponentProjectComponentMetadata,
|
|
8
25
|
} from '../schemas'
|
|
9
26
|
|
|
10
|
-
export const COMPONENT_PROJECT_METADATA_KEY =
|
|
11
|
-
|
|
12
|
-
|
|
27
|
+
export const COMPONENT_PROJECT_METADATA_KEY = VIDEO_RESOURCE_METADATA_KEY
|
|
28
|
+
|
|
29
|
+
export type ComponentProjectComponentMetadata = LegacyComponentProjectComponentMetadata
|
|
13
30
|
|
|
14
31
|
export function defineComponentProjectComponentMetadata(
|
|
15
32
|
metadata: ComponentProjectComponentMetadata,
|
|
16
33
|
): ComponentProjectComponentMetadata {
|
|
17
|
-
return ComponentProjectComponentMetadataSchema.parse(metadata)
|
|
34
|
+
return ComponentProjectComponentMetadataSchema.parse(metadata) as ComponentProjectComponentMetadata
|
|
18
35
|
}
|
|
19
36
|
|
|
20
|
-
|
|
21
|
-
|
|
37
|
+
const sceneAnnotation = createVideoResourceAnnotation(sceneResourceDescriptor)
|
|
38
|
+
const transitionAnnotation = createVideoResourceAnnotation(transitionResourceDescriptor)
|
|
39
|
+
const themeAnnotation = createVideoResourceAnnotation(themeResourceDescriptor)
|
|
22
40
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
41
|
+
function normalizeSceneMetadata(
|
|
42
|
+
metadata: ComponentProjectComponentMetadata | ScenePluginMetadata,
|
|
43
|
+
): ScenePluginMetadata {
|
|
44
|
+
if ('resourceKind' in metadata) {
|
|
45
|
+
return ScenePluginMetadataSchema.parse(metadata)
|
|
26
46
|
}
|
|
47
|
+
|
|
48
|
+
return ScenePluginMetadataSchema.parse({
|
|
49
|
+
resourceKind: 'scene',
|
|
50
|
+
name: metadata.name,
|
|
51
|
+
description: metadata.description,
|
|
52
|
+
sourceFile: metadata.sourceFile,
|
|
53
|
+
aspectRatio: metadata.aspectRatio,
|
|
54
|
+
sceneType: metadata.sceneType,
|
|
55
|
+
sceneFamily: 'custom',
|
|
56
|
+
themePreset: undefined,
|
|
57
|
+
slots: undefined,
|
|
58
|
+
propsTypeName: metadata.propsTypeName,
|
|
59
|
+
rootLayout: 'absolute-fill',
|
|
60
|
+
tags: metadata.tags,
|
|
61
|
+
pluginKey: metadata.name,
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function VideoComponent(
|
|
66
|
+
metadata: ComponentProjectComponentMetadata | ScenePluginMetadata,
|
|
67
|
+
) {
|
|
68
|
+
return sceneAnnotation.annotate(normalizeSceneMetadata(metadata))
|
|
27
69
|
}
|
|
70
|
+
export const TransitionComponent = transitionAnnotation.annotate
|
|
71
|
+
export const ThemeComponent = themeAnnotation.annotate
|
|
72
|
+
|
|
73
|
+
export const defineScenePluginMetadata = defineScenePluginMetadataBase
|
|
74
|
+
export const defineTransitionPluginMetadata = defineTransitionPluginMetadataBase
|
|
75
|
+
export const defineThemePluginMetadata = defineThemePluginMetadataBase
|
|
28
76
|
|
|
29
77
|
export function getComponentProjectComponentMetadata(
|
|
30
78
|
target: unknown,
|
|
31
79
|
): ComponentProjectComponentMetadata | undefined {
|
|
32
|
-
|
|
80
|
+
const metadata = getVideoResourceMetadata<ScenePluginMetadata>(target, 'scene')
|
|
81
|
+
if (!metadata) {
|
|
33
82
|
return undefined
|
|
34
83
|
}
|
|
35
84
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
85
|
+
const { resourceKind, pluginKey, rootLayout, sceneFamily, themePreset, slots, ...legacy } =
|
|
86
|
+
metadata
|
|
87
|
+
void resourceKind
|
|
88
|
+
void pluginKey
|
|
89
|
+
void rootLayout
|
|
90
|
+
void sceneFamily
|
|
91
|
+
void themePreset
|
|
92
|
+
void slots
|
|
93
|
+
return legacy as ComponentProjectComponentMetadata
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function getScenePluginMetadata(target: unknown): ScenePluginMetadata | undefined {
|
|
97
|
+
return getVideoResourceMetadata<ScenePluginMetadata>(target, 'scene')
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function getTransitionPluginMetadata(
|
|
101
|
+
target: unknown,
|
|
102
|
+
): TransitionPluginMetadata | undefined {
|
|
103
|
+
return getVideoResourceMetadata<TransitionPluginMetadata>(target, 'transition')
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function getThemePluginMetadata(target: unknown): ThemePluginMetadata | undefined {
|
|
107
|
+
return getVideoResourceMetadata<ThemePluginMetadata>(target, 'theme')
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export type {
|
|
111
|
+
ScenePluginMetadata,
|
|
112
|
+
ThemePluginMetadata,
|
|
113
|
+
TransitionPluginMetadata,
|
|
114
|
+
VideoResourceMetadata,
|
|
115
|
+
VideoResourceDescriptor,
|
|
40
116
|
}
|
|
@@ -4,183 +4,110 @@ import { tmpdir } from 'node:os'
|
|
|
4
4
|
|
|
5
5
|
import { expect, test } from 'vitest'
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { discoverVideoResources } from './index'
|
|
8
8
|
|
|
9
|
-
test('discovers
|
|
9
|
+
test('discovers scene, transition and theme resources from installed packages', async () => {
|
|
10
10
|
const projectRoot = await fs.mkdtemp(path.join(tmpdir(), 'component-project-helper-discovery-'))
|
|
11
|
-
const
|
|
12
|
-
|
|
11
|
+
const packageRoot = path.join(projectRoot, 'node_modules', '@vibecuting', 'demo-pack')
|
|
12
|
+
const srcRoot = path.join(packageRoot, 'src')
|
|
13
13
|
|
|
14
|
+
await fs.mkdir(srcRoot, { recursive: true })
|
|
14
15
|
await fs.writeFile(
|
|
15
|
-
path.join(
|
|
16
|
-
|
|
17
|
-
@
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
sceneType: 'scene',
|
|
23
|
-
tags: ['layout', 'frame'],
|
|
24
|
-
propsTypeName: 'SceneFrameProps',
|
|
25
|
-
})
|
|
26
|
-
export const SceneFrame = () => null
|
|
27
|
-
`,
|
|
28
|
-
'utf8',
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
await fs.writeFile(
|
|
32
|
-
path.join(componentsDir, 'SceneTitle.tsx'),
|
|
33
|
-
`
|
|
34
|
-
@VideoComponent({
|
|
35
|
-
name: 'SceneTitle',
|
|
36
|
-
description: 'Renders the title block for scene hero content',
|
|
37
|
-
sourceFile: 'src/components/nested/SceneTitle.tsx',
|
|
38
|
-
aspectRatio: '9:16',
|
|
39
|
-
sceneType: 'intro',
|
|
40
|
-
tags: ['title', 'hero'],
|
|
41
|
-
propsTypeName: 'SceneTitleProps',
|
|
42
|
-
})
|
|
43
|
-
export const SceneTitle = () => null
|
|
44
|
-
`,
|
|
45
|
-
'utf8',
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
const discovered = await discoverComponentProjectComponents(projectRoot)
|
|
49
|
-
|
|
50
|
-
expect(discovered).toEqual([
|
|
51
|
-
{
|
|
52
|
-
name: 'SceneFrame',
|
|
53
|
-
description: 'Wraps the scene content in a consistent frame',
|
|
54
|
-
sourceFile: 'src/components/SceneFrame.tsx',
|
|
55
|
-
aspectRatio: '16:9',
|
|
56
|
-
sceneType: 'scene',
|
|
57
|
-
tags: ['layout', 'frame'],
|
|
58
|
-
propsTypeName: 'SceneFrameProps',
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: 'SceneTitle',
|
|
62
|
-
description: 'Renders the title block for scene hero content',
|
|
63
|
-
sourceFile: 'src/components/nested/SceneTitle.tsx',
|
|
64
|
-
aspectRatio: '9:16',
|
|
65
|
-
sceneType: 'intro',
|
|
66
|
-
tags: ['title', 'hero'],
|
|
67
|
-
propsTypeName: 'SceneTitleProps',
|
|
68
|
-
},
|
|
69
|
-
])
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
test('discovers decorated components from installed video-project-core', async () => {
|
|
73
|
-
const projectRoot = await fs.mkdtemp(path.join(tmpdir(), 'component-project-helper-package-'))
|
|
74
|
-
const videoProjectCoreComponentDir = path.join(
|
|
75
|
-
projectRoot,
|
|
76
|
-
'node_modules',
|
|
77
|
-
'@vibecuting',
|
|
78
|
-
'video-project-core',
|
|
79
|
-
'src',
|
|
80
|
-
'core',
|
|
81
|
-
'intro',
|
|
82
|
-
)
|
|
83
|
-
await fs.mkdir(videoProjectCoreComponentDir, { recursive: true })
|
|
84
|
-
|
|
85
|
-
await fs.writeFile(
|
|
86
|
-
path.join(videoProjectCoreComponentDir, 'DefaultIntroBumper.tsx'),
|
|
87
|
-
`
|
|
88
|
-
@VideoComponent({
|
|
89
|
-
name: 'DefaultIntroBumper',
|
|
90
|
-
description: 'Default remotion intro bumper',
|
|
91
|
-
sourceFile: 'node_modules/@vibecuting/video-project-core/src/core/intro/DefaultIntroBumper.tsx',
|
|
92
|
-
aspectRatio: '16:9',
|
|
93
|
-
sceneType: 'intro',
|
|
94
|
-
tags: ['intro', 'core'],
|
|
95
|
-
propsTypeName: 'DefaultIntroBumperProps',
|
|
96
|
-
})
|
|
97
|
-
export const DefaultIntroBumper = () => null
|
|
98
|
-
`,
|
|
16
|
+
path.join(packageRoot, 'package.json'),
|
|
17
|
+
JSON.stringify({
|
|
18
|
+
name: '@vibecuting/demo-pack',
|
|
19
|
+
version: '0.1.0',
|
|
20
|
+
main: './src/index.ts',
|
|
21
|
+
types: './src/index.ts',
|
|
22
|
+
}),
|
|
99
23
|
'utf8',
|
|
100
24
|
)
|
|
101
25
|
|
|
102
|
-
const videoProjectHelperComponentDir = path.join(
|
|
103
|
-
projectRoot,
|
|
104
|
-
'node_modules',
|
|
105
|
-
'@vibecuting',
|
|
106
|
-
'video-project-helper',
|
|
107
|
-
'src',
|
|
108
|
-
'core',
|
|
109
|
-
'scene',
|
|
110
|
-
)
|
|
111
|
-
await fs.mkdir(videoProjectHelperComponentDir, { recursive: true })
|
|
112
|
-
|
|
113
26
|
await fs.writeFile(
|
|
114
|
-
path.join(
|
|
27
|
+
path.join(srcRoot, 'index.ts'),
|
|
115
28
|
`
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
29
|
+
export const sceneMetadata = defineScenePluginMetadata({
|
|
30
|
+
resourceKind: 'scene',
|
|
31
|
+
name: 'DemoScene',
|
|
32
|
+
description: 'Demo scene resource',
|
|
33
|
+
sourceFile: 'src/index.ts',
|
|
34
|
+
pluginKey: 'demo.scene',
|
|
35
|
+
tags: ['demo'],
|
|
120
36
|
aspectRatio: '16:9',
|
|
121
37
|
sceneType: 'scene',
|
|
122
|
-
|
|
123
|
-
|
|
38
|
+
sceneFamily: 'custom',
|
|
39
|
+
rootLayout: 'absolute-fill',
|
|
124
40
|
})
|
|
125
|
-
export const DefaultSceneFrame = () => null
|
|
126
|
-
`,
|
|
127
|
-
'utf8',
|
|
128
|
-
)
|
|
129
41
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
tags: ['intro', 'core'],
|
|
140
|
-
propsTypeName: 'DefaultIntroBumperProps',
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
name: 'DefaultSceneFrame',
|
|
144
|
-
description: 'Default helper scene frame',
|
|
145
|
-
sourceFile:
|
|
146
|
-
'node_modules/@vibecuting/video-project-helper/src/core/scene/DefaultSceneFrame.tsx',
|
|
147
|
-
aspectRatio: '16:9',
|
|
148
|
-
sceneType: 'scene',
|
|
149
|
-
tags: ['scene', 'helper'],
|
|
150
|
-
propsTypeName: 'DefaultSceneFrameProps',
|
|
151
|
-
},
|
|
152
|
-
])
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
test('ignores test files from installed packages', async () => {
|
|
156
|
-
const projectRoot = await fs.mkdtemp(path.join(tmpdir(), 'component-project-helper-tests-'))
|
|
157
|
-
const packageTestDir = path.join(
|
|
158
|
-
projectRoot,
|
|
159
|
-
'node_modules',
|
|
160
|
-
'@vibecuting',
|
|
161
|
-
'video-project-helper',
|
|
162
|
-
'src',
|
|
163
|
-
)
|
|
164
|
-
await fs.mkdir(packageTestDir, { recursive: true })
|
|
42
|
+
export const transitionMetadata = defineTransitionPluginMetadata({
|
|
43
|
+
resourceKind: 'transition',
|
|
44
|
+
name: 'DemoTransition',
|
|
45
|
+
description: 'Demo transition resource',
|
|
46
|
+
sourceFile: 'src/index.ts',
|
|
47
|
+
pluginKey: 'demo.transition',
|
|
48
|
+
tags: ['demo'],
|
|
49
|
+
transitionKind: 'transition',
|
|
50
|
+
})
|
|
165
51
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
tags: ['test'],
|
|
176
|
-
propsTypeName: 'ShouldBeIgnoredProps',
|
|
52
|
+
export const themeMetadata = defineThemePluginMetadata({
|
|
53
|
+
resourceKind: 'theme',
|
|
54
|
+
name: 'DemoTheme',
|
|
55
|
+
description: 'Demo theme resource',
|
|
56
|
+
sourceFile: 'src/index.ts',
|
|
57
|
+
pluginKey: 'demo.theme',
|
|
58
|
+
tags: ['demo'],
|
|
59
|
+
supportedSceneFamilies: ['custom'],
|
|
60
|
+
cssVariables: ['--scene-bg'],
|
|
177
61
|
})
|
|
178
|
-
|
|
62
|
+
|
|
63
|
+
export const DemoScene = VideoComponent(sceneMetadata)(
|
|
64
|
+
defineSceneComponent({
|
|
65
|
+
family: 'custom',
|
|
66
|
+
propsSchema: null,
|
|
67
|
+
component: function DemoScene() {
|
|
68
|
+
return null
|
|
69
|
+
},
|
|
70
|
+
}),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
export const DemoTransition = TransitionComponent(transitionMetadata)(
|
|
74
|
+
defineTransitionPlugin({
|
|
75
|
+
key: 'demo.transition',
|
|
76
|
+
kind: 'transition',
|
|
77
|
+
metadata: transitionMetadata,
|
|
78
|
+
propsSchema: null,
|
|
79
|
+
renderBoundary: () => null,
|
|
80
|
+
getBoundaryDurationInFrames: () => 1,
|
|
81
|
+
getTimelineOverlapInFrames: () => 1,
|
|
82
|
+
}),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
export const DemoTheme = ThemeComponent(themeMetadata)(
|
|
86
|
+
defineSceneTheme({
|
|
87
|
+
key: 'demo.theme',
|
|
88
|
+
name: 'Demo theme',
|
|
89
|
+
variables: {
|
|
90
|
+
'--scene-bg': '#000000',
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
93
|
+
)
|
|
179
94
|
`,
|
|
180
95
|
'utf8',
|
|
181
96
|
)
|
|
182
97
|
|
|
183
|
-
const discovered = await
|
|
98
|
+
const discovered = await discoverVideoResources(projectRoot)
|
|
184
99
|
|
|
185
|
-
expect(discovered).toEqual([
|
|
100
|
+
expect(discovered.map((resource) => resource.exportName)).toEqual([
|
|
101
|
+
'DemoScene',
|
|
102
|
+
'DemoTheme',
|
|
103
|
+
'DemoTransition',
|
|
104
|
+
])
|
|
105
|
+
expect(discovered.map((resource) => resource.metadata.resourceKind)).toEqual([
|
|
106
|
+
'scene',
|
|
107
|
+
'theme',
|
|
108
|
+
'transition',
|
|
109
|
+
])
|
|
110
|
+
expect(discovered[0]?.metadata.pluginKey).toBe('demo.scene')
|
|
111
|
+
expect(discovered[1]?.metadata.pluginKey).toBe('demo.theme')
|
|
112
|
+
expect(discovered[2]?.metadata.pluginKey).toBe('demo.transition')
|
|
186
113
|
})
|