vue-component-meta 3.2.4 → 3.2.6

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 CHANGED
@@ -1,194 +1,177 @@
1
1
  # vue-component-meta
2
2
 
3
- `vue-component-meta` allows you to extract the meta-data like props, slots, events, etc from your components via static code analysis. You can even generate description for your props from your source code. This helps document your components via automation. Please refer to the [reference](#reference) section for references.
3
+ <p>
4
+ <a href="https://www.npmjs.com/package/vue-component-meta"><img src="https://img.shields.io/npm/v/vue-component-meta.svg?labelColor=18181B&color=1584FC" alt="NPM version"></a>
5
+ <a href="https://github.com/vuejs/language-tools/blob/master/LICENSE"><img src="https://img.shields.io/github/license/vuejs/language-tools.svg?labelColor=18181B&color=1584FC" alt="License"></a>
6
+ </p>
4
7
 
5
- ## Guide 📗
8
+ Statically extract metadata such as props, events, slots, and exposed from Vue components. Useful for auto-generating component documentation or displaying component APIs in tools like Storybook.
6
9
 
7
- First of all, you need to create a component meta checker using `createChecker`:
10
+ ## Installation
8
11
 
9
- ```ts
10
- import * as url from 'url'
11
- import path from 'path'
12
+ ```bash
13
+ npm install vue-component-meta typescript
14
+ ```
12
15
 
13
- import type { MetaCheckerOptions } from 'vue-component-meta'
14
- import { createChecker } from 'vue-component-meta'
16
+ ## Usage
15
17
 
16
- const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
18
+ ### Create a Checker from tsconfig.json
17
19
 
18
- const checkerOptions: MetaCheckerOptions = {
19
- forceUseTs: true,
20
- schema: { ignore: ['MyIgnoredNestedProps'] },
21
- printer: { newLine: 1 },
22
- }
20
+ ```typescript
21
+ import { createChecker } from 'vue-component-meta';
23
22
 
24
- const tsconfigChecker = createChecker(
25
- // Write your tsconfig path
26
- path.join(__dirname, 'path-to-tsconfig'),
27
- checkerOptions,
28
- )
29
- ```
23
+ const checker = createChecker('/path/to/tsconfig.json', {
24
+ schema: true, // Enable schema parsing
25
+ });
30
26
 
31
- Now, you can extract the component meta using `getComponentMeta` method of checker:
27
+ const meta = checker.getComponentMeta('/path/to/MyComponent.vue');
28
+ ```
32
29
 
33
- ```ts
34
- import * as url from 'url'
35
- import path from 'path'
30
+ ### Create a Checker from JSON Configuration
36
31
 
37
- const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
32
+ ```typescript
33
+ import { createCheckerByJson } from 'vue-component-meta';
38
34
 
39
- const componentPath = path.join(__dirname, 'path-to-component');
40
- const meta = checker.getComponentMeta(componentPath);
35
+ const checker = createCheckerByJson('/project/root', {
36
+ include: ['src/**/*.vue'],
37
+ compilerOptions: { /* ... */ },
38
+ vueCompilerOptions: { /* ... */ },
39
+ });
41
40
  ```
42
41
 
43
- This meta contains really useful stuff like component props, slots, events and more. You can refer to its [type definition](https://github.com/vuejs/language-tools/blob/master/packages/component-meta/lib/types.ts) for more details.
42
+ ## API
44
43
 
45
- ### Extracting component name and description
44
+ ### `checker.getComponentMeta(filePath, exportName?)`
46
45
 
47
- The component meta also includes `name` and `description` fields at the root level:
46
+ Get the metadata of a component. `exportName` defaults to `'default'`.
48
47
 
49
- - **`name`**: Extracted from the `name` property in the component options (for Options API components)
50
- - **`description`**: Extracted from JSDoc comments above the component export (for TypeScript/JavaScript files)
48
+ The returned `ComponentMeta` object contains:
51
49
 
52
- ```ts
53
- /**
54
- * My awesome component description
55
- */
56
- export default defineComponent({
57
- name: 'MyComponent',
58
- // ... component definition
59
- })
50
+ ```typescript
51
+ interface ComponentMeta {
52
+ name?: string;
53
+ description?: string;
54
+ type: TypeMeta;
55
+ props: PropertyMeta[];
56
+ events: EventMeta[];
57
+ slots: SlotMeta[];
58
+ exposed: ExposeMeta[];
59
+ }
60
60
  ```
61
61
 
62
- When you extract the component meta, you'll get:
63
- ```ts
64
- meta.name // 'MyComponent'
65
- meta.description // 'My awesome component description'
66
- ```
62
+ ### `checker.getExportNames(filePath)`
67
63
 
68
- ### Extracting prop meta
64
+ Get all export names of a file.
69
65
 
70
- `vue-component-meta` will automatically extract the prop details like its name, default value, is required or not, etc. Additionally, you can even write prop description in source code via [JSDoc](https://jsdoc.app/) comment for that prop.
66
+ ### `checker.updateFile(filePath, content)`
71
67
 
72
- ```ts
73
- /**
74
- * Hide/Show alert based on v-model value
75
- */
76
- modelValue: {
77
- type: Boolean,
78
- default: null,
79
- },
80
- ```
68
+ Update file content (for virtual files or live editing).
69
+
70
+ ### `checker.deleteFile(filePath)`
71
+
72
+ Remove a file from the project.
73
+
74
+ ### `checker.reload()`
81
75
 
82
- When you extract the component meta and extract the `description` property of that prop it will be "Hide/Show alert based on v-model value" 😍
76
+ Reload the tsconfig.json configuration.
83
77
 
84
- > **Warning**
85
- >
86
- > Do note that `meta.props` will be array of props so you can't access it via `meta.props.<prop-name>`. Moreover, `meta.props` will also contain some global prop which you can identify via `prop.global` property.
78
+ ### `checker.clearCache()`
87
79
 
88
- You can use it to document your component as you build your project without writing additional documentation.
80
+ Clear cached file content.
89
81
 
90
- ## Pitfalls 👀
82
+ ### `checker.getProgram()`
91
83
 
92
- As `vue-component-meta` uses static code analysis, it can't extract the dynamic prop definition.
84
+ Get the underlying TypeScript Program instance.
93
85
 
94
- ### default value
86
+ ## Metadata Structures
95
87
 
96
- `vue-component-meta` won't be able to extract default value for prop as props can't be analyzed.
88
+ ### PropertyMeta (Props)
97
89
 
98
- ```ts
99
- props: {
100
- // Props definition by function execution
101
- ...useLayerProps({
102
- color: {
103
- default: 'primary',
104
- },
105
- variant: {
106
- default: 'light',
107
- },
108
- }),
90
+ ```typescript
91
+ interface PropertyMeta {
92
+ name: string;
93
+ description: string; // Read from JSDoc
94
+ type: string; // Type string
95
+ default?: string; // Default value
96
+ required: boolean;
97
+ global: boolean; // Whether it's a global prop
98
+ tags: { name: string; text?: string }[]; // JSDoc tags
99
+ schema: PropertyMetaSchema;
100
+ getDeclarations(): Declaration[];
101
+ getTypeObject(): ts.Type;
109
102
  }
110
103
  ```
111
104
 
112
- In this scenario, to get the correct default value you can let `vue-component-meta` know it by writing them explicitly:
113
-
114
- ```ts
115
- props: {
116
- // let vue-component-meta found it
117
- color: { default: 'primary' },
118
- variant: { default: 'light' },
119
-
120
- // Props definition by function execution
121
- ...useLayerProps({
122
- color: {
123
- default: 'primary',
124
- },
125
- variant: {
126
- default: 'light',
127
- },
128
- }),
105
+ ### EventMeta
106
+
107
+ ```typescript
108
+ interface EventMeta {
109
+ name: string;
110
+ description: string;
111
+ type: string;
112
+ signature: string;
113
+ tags: { name: string; text?: string }[];
114
+ schema: PropertyMetaSchema[];
115
+ getDeclarations(): Declaration[];
116
+ getTypeObject(): ts.Type | undefined;
129
117
  }
130
118
  ```
131
119
 
132
- ### description
133
-
134
- Same as above scenario you might have issue with description not generating when prop definition is dynamic. In this case writing prop description can be tricky.
135
-
136
- When it's function execution, write prop description in function definition:
137
-
138
- ```ts
139
- export const useLayerProp = (...) => {
140
- const props = {
141
- /**
142
- * Layer variant
143
- */
144
- variant: {
145
- type: String,
146
- default: 'text',
147
- },
148
- }
149
-
150
- export { props }
120
+ ### SlotMeta
121
+
122
+ ```typescript
123
+ interface SlotMeta {
124
+ name: string;
125
+ description: string;
126
+ type: string;
127
+ tags: { name: string; text?: string }[];
128
+ schema: PropertyMetaSchema;
129
+ getDeclarations(): Declaration[];
130
+ getTypeObject(): ts.Type;
151
131
  }
152
132
  ```
153
133
 
154
- ### required
155
-
156
- For generating the correct `required` value for props like below:
157
-
158
- ```ts
159
- // @/composables/useProps.ts
160
- export const disabled = {
161
- type: Boolean,
162
- default: false,
134
+ ### ExposeMeta
135
+
136
+ ```typescript
137
+ interface ExposeMeta {
138
+ name: string;
139
+ description: string;
140
+ type: string;
141
+ tags: { name: string; text?: string }[];
142
+ schema: PropertyMetaSchema;
143
+ getDeclarations(): Declaration[];
144
+ getTypeObject(): ts.Type;
163
145
  }
164
146
  ```
165
147
 
166
- ```ts
167
- import { disabled } from '@/composables/useProps'
148
+ ## Options
168
149
 
169
- export default defineComponent({
170
- props: {
171
- disabled,
172
- },
173
- })
150
+ ```typescript
151
+ interface MetaCheckerOptions {
152
+ schema?: boolean | {
153
+ ignore?: (string | ((name: string, type: ts.Type, typeChecker: ts.TypeChecker) => boolean))[];
154
+ };
155
+ printer?: ts.PrinterOptions;
156
+ }
174
157
  ```
175
158
 
176
- You need to add `as const` to variable definition:
159
+ ### `schema`
177
160
 
178
- ```diff
179
- export const disabled = {
180
- type: Boolean,
181
- default: false,
182
- - }
183
- + } as const
161
+ Controls whether to parse the schema structure of types. Set to `true` to enable, or pass an object to configure types to ignore.
162
+
163
+ ```typescript
164
+ const checker = createChecker(tsconfig, {
165
+ schema: {
166
+ ignore: ['HTMLElement', (name) => name.startsWith('Internal')],
167
+ },
168
+ });
184
169
  ```
185
170
 
186
- ## Used by 🎉
171
+ ## Related Packages
187
172
 
188
- - [Anu](https://github.com/jd-solanki/anu) UI library uses `vue-component-meta` to generate components' API via [automation](https://github.com/jd-solanki/anu/blob/main/scripts/gen-component-meta.ts).
173
+ - [`vue-component-type-helpers`](../component-type-helpers) - Type helper utilities
189
174
 
190
- ## Reference 📚
175
+ ## License
191
176
 
192
- - [tests](https://github.com/vuejs/language-tools/blob/master/packages/component-meta/tests/index.spec.ts)
193
- - [Anu's components' API automation](https://github.com/jd-solanki/anu/blob/main/scripts/gen-component-meta.ts)
194
- - [Discord chat for dynamic usage](https://discord.com/channels/793943652350427136/1027819645677350912)
177
+ [MIT](https://github.com/vuejs/language-tools/blob/master/LICENSE) License
package/lib/checker.js CHANGED
@@ -109,7 +109,7 @@ function createCheckerBase(ts, getConfigAndFiles, checkerOptions, rootPath) {
109
109
  }
110
110
  const checker = program.getTypeChecker();
111
111
  const componentType = checker.getTypeAtLocation(componentNode);
112
- return (0, componentMeta_1.getComponentMeta)(ts, checker, printer, language, componentNode, componentType, checkerOptions.schema ?? false, {
112
+ return (0, componentMeta_1.getComponentMeta)(ts, checker, printer, language, fileName => language.scripts.get(fileName), componentNode, componentType, checkerOptions.schema ?? false, {
113
113
  noDeclarations: checkerOptions.noDeclarations ?? true,
114
114
  rawType: checkerOptions.rawType ?? false,
115
115
  });
@@ -1,7 +1,7 @@
1
1
  import * as core from '@vue/language-core';
2
2
  import type * as ts from 'typescript';
3
3
  import type { ComponentMeta, MetaCheckerSchemaOptions } from './types';
4
- export declare function getComponentMeta(ts: typeof import('typescript'), typeChecker: ts.TypeChecker, printer: ts.Printer, language: core.Language<string>, componentNode: ts.Node, componentType: ts.Type, options: MetaCheckerSchemaOptions, deprecatedOptions?: {
4
+ export declare function getComponentMeta(ts: typeof import('typescript'), typeChecker: ts.TypeChecker, printer: ts.Printer, language: core.Language, getSourceScript: (fileName: string) => core.SourceScript | undefined, componentNode: ts.Node, componentType: ts.Type, options: MetaCheckerSchemaOptions, deprecatedOptions?: {
5
5
  noDeclarations: boolean;
6
6
  rawType: boolean;
7
7
  }): ComponentMeta;
@@ -38,7 +38,7 @@ const core = __importStar(require("@vue/language-core"));
38
38
  const helpers_1 = require("./helpers");
39
39
  const schemaResolvers_1 = require("./schemaResolvers");
40
40
  const scriptSetup_1 = require("./scriptSetup");
41
- function getComponentMeta(ts, typeChecker, printer, language, componentNode, componentType, options, deprecatedOptions = { noDeclarations: true, rawType: false }) {
41
+ function getComponentMeta(ts, typeChecker, printer, language, getSourceScript, componentNode, componentType, options, deprecatedOptions = { noDeclarations: true, rawType: false }) {
42
42
  const componentSymbol = typeChecker.getSymbolAtLocation(componentNode);
43
43
  let componentFile = componentNode.getSourceFile();
44
44
  if (componentSymbol) {
@@ -95,11 +95,11 @@ function getComponentMeta(ts, typeChecker, printer, language, componentNode, com
95
95
  const eventProps = new Set(meta.events.map(event => `on${event.name.charAt(0).toUpperCase()}${event.name.slice(1)}`));
96
96
  result = properties
97
97
  .map(prop => {
98
- const { resolveNestedProperties, } = (0, schemaResolvers_1.createSchemaResolvers)(ts, typeChecker, printer, language, options, deprecatedOptions);
98
+ const { resolveNestedProperties, } = (0, schemaResolvers_1.createSchemaResolvers)(ts, typeChecker, printer, language, getSourceScript, options, deprecatedOptions);
99
99
  return resolveNestedProperties(prop);
100
100
  })
101
101
  .filter((prop) => !!prop && !eventProps.has(prop.name));
102
- const defaults = (0, scriptSetup_1.getDefaultsFromScriptSetup)(ts, printer, language, componentFile.fileName);
102
+ const defaults = (0, scriptSetup_1.getDefaultsFromScriptSetup)(ts, printer, getSourceScript(componentFile.fileName));
103
103
  for (const prop of result) {
104
104
  if (prop.name.match(/^onVnode[A-Z]/)) {
105
105
  prop.name = 'onVue:' + prop.name['onVnode'.length]?.toLowerCase() + prop.name.slice('onVnode'.length + 1);
@@ -113,7 +113,7 @@ function getComponentMeta(ts, typeChecker, printer, language, componentNode, com
113
113
  if (emitType) {
114
114
  const calls = emitType.getCallSignatures();
115
115
  return calls.map(call => {
116
- const { resolveEventSignature, } = (0, schemaResolvers_1.createSchemaResolvers)(ts, typeChecker, printer, language, options, deprecatedOptions);
116
+ const { resolveEventSignature, } = (0, schemaResolvers_1.createSchemaResolvers)(ts, typeChecker, printer, language, getSourceScript, options, deprecatedOptions);
117
117
  return resolveEventSignature(call);
118
118
  }).filter(event => event.name);
119
119
  }
@@ -124,7 +124,7 @@ function getComponentMeta(ts, typeChecker, printer, language, componentNode, com
124
124
  if (slotsType) {
125
125
  const properties = slotsType.getProperties();
126
126
  return properties.map(prop => {
127
- const { resolveSlotProperties, } = (0, schemaResolvers_1.createSchemaResolvers)(ts, typeChecker, printer, language, options, deprecatedOptions);
127
+ const { resolveSlotProperties, } = (0, schemaResolvers_1.createSchemaResolvers)(ts, typeChecker, printer, language, getSourceScript, options, deprecatedOptions);
128
128
  return resolveSlotProperties(prop);
129
129
  });
130
130
  }
@@ -144,7 +144,7 @@ function getComponentMeta(ts, typeChecker, printer, language, componentNode, com
144
144
  // Exclude $slots
145
145
  && prop.name !== '$slots');
146
146
  return properties.map(prop => {
147
- const { resolveExposedProperties, } = (0, schemaResolvers_1.createSchemaResolvers)(ts, typeChecker, printer, language, options, deprecatedOptions);
147
+ const { resolveExposedProperties, } = (0, schemaResolvers_1.createSchemaResolvers)(ts, typeChecker, printer, language, getSourceScript, options, deprecatedOptions);
148
148
  return resolveExposedProperties(prop);
149
149
  });
150
150
  }
@@ -1,7 +1,7 @@
1
1
  import type * as core from '@vue/language-core';
2
2
  import type * as ts from 'typescript';
3
3
  import type { EventMeta, ExposeMeta, PropertyMeta, PropertyMetaSchema, SlotMeta } from './types';
4
- export declare function createSchemaResolvers(ts: typeof import('typescript'), typeChecker: ts.TypeChecker, printer: ts.Printer, language: core.Language<string>, options: import('./types').MetaCheckerSchemaOptions, deprecatedOptions: {
4
+ export declare function createSchemaResolvers(ts: typeof import('typescript'), typeChecker: ts.TypeChecker, printer: ts.Printer, language: core.Language, getSourceScript: (fileName: string) => core.SourceScript | undefined, options: import('./types').MetaCheckerSchemaOptions, deprecatedOptions: {
5
5
  noDeclarations: boolean;
6
6
  rawType: boolean;
7
7
  }): {
@@ -8,7 +8,7 @@ const publicPropsInterfaces = new Set([
8
8
  'AllowedComponentProps',
9
9
  'ComponentCustomProps',
10
10
  ]);
11
- function createSchemaResolvers(ts, typeChecker, printer, language, options, deprecatedOptions) {
11
+ function createSchemaResolvers(ts, typeChecker, printer, language, getSourceScript, options, deprecatedOptions) {
12
12
  const visited = new Set();
13
13
  function shouldIgnore(subtype) {
14
14
  const name = getFullyQualifiedName(subtype);
@@ -311,7 +311,7 @@ function createSchemaResolvers(ts, typeChecker, printer, language, options, depr
311
311
  }
312
312
  function getDeclaration(declaration) {
313
313
  const fileName = declaration.getSourceFile().fileName;
314
- const sourceScript = language.scripts.get(fileName);
314
+ const sourceScript = getSourceScript(fileName);
315
315
  if (sourceScript?.generated) {
316
316
  const script = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root);
317
317
  if (script) {
@@ -319,7 +319,7 @@ function createSchemaResolvers(ts, typeChecker, printer, language, options, depr
319
319
  for (const [start] of map.toSourceLocation(declaration.getStart())) {
320
320
  for (const [end] of map.toSourceLocation(declaration.getEnd())) {
321
321
  return {
322
- file: sourceScript.id,
322
+ file: String(sourceScript.id),
323
323
  range: [start, end],
324
324
  };
325
325
  }
@@ -1,4 +1,4 @@
1
1
  import * as core from '@vue/language-core';
2
2
  import type * as ts from 'typescript';
3
- export declare function getDefaultsFromScriptSetup(ts: typeof import('typescript'), printer: ts.Printer, language: core.Language<string>, componentPath: string): Map<string, string> | undefined;
3
+ export declare function getDefaultsFromScriptSetup(ts: typeof import('typescript'), printer: ts.Printer, sourceScript: core.SourceScript | undefined): Map<string, string> | undefined;
4
4
  export declare function resolveDefaultOptionExpression(ts: typeof import('typescript'), _default: ts.Expression): ts.Expression;
@@ -36,8 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.getDefaultsFromScriptSetup = getDefaultsFromScriptSetup;
37
37
  exports.resolveDefaultOptionExpression = resolveDefaultOptionExpression;
38
38
  const core = __importStar(require("@vue/language-core"));
39
- function getDefaultsFromScriptSetup(ts, printer, language, componentPath) {
40
- const sourceScript = language.scripts.get(componentPath);
39
+ function getDefaultsFromScriptSetup(ts, printer, sourceScript) {
41
40
  const virtualCode = sourceScript?.generated?.root;
42
41
  if (!virtualCode) {
43
42
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue-component-meta",
3
- "version": "3.2.4",
3
+ "version": "3.2.6",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "**/*.js",
@@ -13,8 +13,8 @@
13
13
  "directory": "packages/component-meta"
14
14
  },
15
15
  "dependencies": {
16
- "@volar/typescript": "2.4.27",
17
- "@vue/language-core": "3.2.4",
16
+ "@volar/typescript": "2.4.28",
17
+ "@vue/language-core": "3.2.6",
18
18
  "path-browserify": "^1.0.1"
19
19
  },
20
20
  "devDependencies": {
@@ -29,5 +29,5 @@
29
29
  "optional": true
30
30
  }
31
31
  },
32
- "gitHead": "f0ede303fadb192a59068b4b667b0405523d24c8"
32
+ "gitHead": "94907be4f056f25867e46a117ab18d2782b425d7"
33
33
  }