Skip to content

Commit ae1d269

Browse files
authored
Fix typings (#439)
1 parent 8f95816 commit ae1d269

File tree

8 files changed

+115
-41
lines changed

8 files changed

+115
-41
lines changed

packages/cheetah-grid/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cheetah-grid",
3-
"version": "1.16.0",
3+
"version": "1.16.2",
44
"description": "Cheetah Grid is a high performance grid engine that works on canvas",
55
"keywords": [
66
"spreadsheet",

packages/cheetah-grid/src/js/main.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ export { getInternal as _getInternal } from "./get-internal";
2525
* @namespace cheetahGrid
2626
*/
2727
export {
28-
/**
29-
* Types
30-
* @namespace cheetahGrid.TYPES
31-
*/
32-
TYPES,
3328
core,
3429
tools,
3530
// impl Grids
@@ -52,6 +47,14 @@ export {
5247
register,
5348
};
5449

50+
export type {
51+
/**
52+
* Types
53+
* @namespace cheetahGrid.TYPES
54+
*/
55+
TYPES,
56+
};
57+
5558
/** @private */
5659
function getIcons(): { [key: string]: TYPES.IconDefine } {
5760
return icons.get();

packages/cheetah-grid/src/js/ts-types/grid-engine.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import type {
2222
StylePropertyFunctionArg,
2323
TextOverflow,
2424
} from "./define";
25-
import type { ColumnDefine } from "../ListGrid";
25+
import type { ColumnDefine, HeadersDefine } from "../list-grid/layout-map/api";
2626
import type { RecordBoolean } from "./column";
2727
import type { RequiredThemeDefine } from "./plugin";
2828
import type { SimpleColumnIconOption } from "../ts-types-internal/data";
@@ -162,6 +162,7 @@ export interface ListGridAPI<T> extends DrawGridAPI {
162162
dataSource: DataSourceAPI<T>;
163163
theme: RequiredThemeDefine | null;
164164
allowRangePaste: boolean;
165+
header: HeadersDefine<T>;
165166
headerRowHeight: number[] | number;
166167
sortState: SortState | null;
167168
headerValues: HeaderValues;

packages/cheetah-grid/src/js/ts-types/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ export * from "./plugin";
66
export * from "./define";
77
export * from "./data";
88
export * from "./grid-engine";
9+
10+
export type { ColumnDefine, HeadersDefine } from "../list-grid/layout-map/api";

packages/vue-cheetah-grid/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-cheetah-grid",
3-
"version": "1.16.1",
3+
"version": "1.16.2",
44
"description": "Cheetah Grid for Vue.js",
55
"main": "lib/index.js",
66
"unpkg": "dist/vueCheetahGrid.js",

packages/vue-cheetah-grid/scripts/lib/merge.js

+24-6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module.exports = {
88
const merge = require('deepmerge')
99
const c = merge.all(components)
1010
c.props = mergeProps(components)
11+
c.methods = mergeMethods(components)
1112
return c
1213
}
1314
}
@@ -27,15 +28,15 @@ const PROPS = [
2728

2829
function mergeProps (components) {
2930
const props = components.flatMap(c => c.props)
30-
const mergeProps = []
31+
const mergedProps = []
3132
for (const prop of props) {
32-
const idx = mergeProps.findIndex((t) => t.name === prop.name)
33+
const idx = mergedProps.findIndex((t) => t.name === prop.name)
3334
if (idx >= 0) {
34-
mergeProps.splice(idx, 1)
35+
mergedProps.splice(idx, 1)
3536
}
36-
mergeProps.push(prop)
37+
mergedProps.push(prop)
3738
}
38-
mergeProps.sort((a, b) => {
39+
mergedProps.sort((a, b) => {
3940
const ai = PROPS.indexOf(a.name)
4041
const bi = PROPS.indexOf(b.name)
4142
if (ai >= 0 && bi >= 0) {
@@ -50,7 +51,24 @@ function mergeProps (components) {
5051
return compare(a.name, b.name)
5152
})
5253

53-
return mergeProps
54+
return mergedProps
55+
}
56+
57+
function mergeMethods (components) {
58+
const methods = components.flatMap(c => c.methods)
59+
const mergedMethods = []
60+
for (const method of methods) {
61+
const idx = mergedMethods.findIndex((t) => t.name === method.name)
62+
if (idx >= 0) {
63+
mergedMethods.splice(idx, 1)
64+
}
65+
mergedMethods.push(method)
66+
}
67+
mergedMethods.sort((a, b) => {
68+
return compare(a.name, b.name)
69+
})
70+
71+
return mergedMethods
5472
}
5573

5674
function compare (a, b) {

packages/vue-cheetah-grid/scripts/lib/metadata.js

+54-6
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,42 @@ const path = require('path')
33
const vuedoc = require('@vuedoc/md')
44
const merge = require('./merge')
55

6+
/**
7+
* @typedef {object} Keyword
8+
* @property {string} name
9+
* @property {string} description
10+
*/
611
/**
712
* @typedef {object} ComponentPropMetadata
813
* @property {string} name
914
* @property {string} description
10-
* @property {{ name: string, description: string }[]} keywords
15+
* @property {Keyword[]} keywords
1116
* @property {string | { type: string, required: boolean, default: any }} value
1217
*/
18+
/**
19+
* @typedef {object} ComponentMethodMetadata
20+
* @property {string} name
21+
* @property {string} description
22+
* @property {Keyword[]} keywords
23+
* @property {{ type: 'FunctionExpression' }} value
24+
* @property {'public'|undefined} visibility
25+
* @property {string[]} args
26+
* @property {unknown} return
27+
*/
1328
/**
1429
* @typedef {object} ComponentMetadata
1530
* @property {string} name
1631
* @property {string} description
17-
* @property {{ name: string, description: string }[]} keywords
32+
* @property {Keyword[]} keywords
1833
* @property {ComponentPropMetadata[]} props
34+
* @property {ComponentMethodMetadata[]} methods
1935
*/
2036

2137
module.exports = {
2238
getAllVueComponentMetadata,
2339
getPropType,
24-
isRequiredProp
40+
isRequiredProp,
41+
getMethodSignature
2542
}
2643

2744
/**
@@ -55,17 +72,48 @@ async function getAllVueComponentMetadata () {
5572
/**
5673
* @param {ComponentPropMetadata} prop
5774
*/
58-
5975
function getPropType (prop) {
6076
const customTypeKeyword = prop.keywords.find(({ name, description }) => name === 'type' && description)
61-
const customType = customTypeKeyword && customTypeKeyword.description.replace(/\{(.+?)\}/, '$1')
77+
const customType = customTypeKeyword && getKeywordType(customTypeKeyword)
6278
const type = customType || prop.value.type || prop.value || 'any'
6379
return parseType(type)
6480
}
81+
6582
/**
66-
* @param {ComponentPropMetadata} prop
83+
* @param {ComponentMethodMetadata} method
6784
*/
85+
function getMethodSignature (method) {
86+
const paramKeywords = {}
87+
for (const keyword of method.keywords.filter(({ name, description }) => name === 'param')) {
88+
const typeClosing = keyword.description.indexOf('}')
89+
if (typeClosing < 0) continue
90+
const paramNameAndDesc = keyword.description.slice(typeClosing + 1).trim()
91+
const props = /^\[?(\p{ID_Start}\p{ID_Continue}*(?:\.\p{ID_Start}\p{ID_Continue}*)*)/u.exec(paramNameAndDesc)[1].split('.')
92+
if (props.length === 1) {
93+
paramKeywords[props[0]] = getKeywordType(keyword)
94+
}
95+
}
6896

97+
const argsSignature = method.args
98+
.map(arg => {
99+
const keyword = paramKeywords[arg]
100+
return (keyword && getKeywordType(keyword)) || 'any'
101+
})
102+
.join(', ')
103+
const returnKeyword = method.keywords.find(({ name, description }) => name === 'return' && description)
104+
const returnType = (returnKeyword && getKeywordType(returnKeyword)) || 'any'
105+
return `(${argsSignature}) => ${returnType}`
106+
}
107+
/**
108+
* @param {Keyword} keyword
109+
*/
110+
function getKeywordType (keyword) {
111+
return /^\s*\{(.+)\}/u.exec(keyword.description)?.[1]
112+
}
113+
114+
/**
115+
* @param {ComponentPropMetadata} prop
116+
*/
69117
function isRequiredProp (prop) {
70118
return typeof prop.value !== 'string' && Boolean(prop.value.required)
71119
}

packages/vue-cheetah-grid/scripts/vue3-types.js

+23-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const fs = require('fs')
22
const path = require('path')
3-
const { getAllVueComponentMetadata, getPropType, isRequiredProp } = require('./lib/metadata')
3+
const { getAllVueComponentMetadata, getPropType, isRequiredProp, getMethodSignature } = require('./lib/metadata')
44
const cheetahGrid = require('cheetah-grid')
55
const { EVENT_TYPE } = cheetahGrid.ListGrid
66
const vue3Emits = Object.keys(EVENT_TYPE)
@@ -25,21 +25,34 @@ async function main () {
2525
${camelCase(prop.name)}${isRequiredProp(prop) ? '' : '?'}: ${normalizePropType(prop)};
2626
`.trim()
2727
})
28+
const methods = component.methods
29+
.filter(method => method.visibility === 'public')
30+
.map(method => {
31+
return `
32+
/** ${method.description} */
33+
${method.name}: ${getMethodSignature(method)};
34+
`.trim()
35+
})
2836
const emits = Object.keys(vue3Emits).map(emitName => {
2937
return `
3038
on${pascalCase(emitName)}?: Function;
3139
`.trim()
3240
})
3341
componentTypes.push(`
3442
/** ${component.description} */
35-
export type ${componentName} = GlobalComponentConstructor<{
36-
${indent([...props, ...emits].join('\n'), 2)}
37-
}>;
43+
export const ${componentName}: ComponentConstructor<
44+
{
45+
${indent([...props, ...emits].join('\n'), 4)}
46+
},
47+
{
48+
${indent(methods.join('\n'), 4)}
49+
}
50+
>;
3851
`.trim())
3952
components.push(`
4053
/** ${component.description} */
41-
${componentName}: ${componentName};
42-
"${kebabCase(componentName)}": ${componentName};
54+
${componentName}: typeof ${componentName};
55+
"${kebabCase(componentName)}": typeof ${componentName};
4356
`.trim())
4457
}
4558

@@ -49,25 +62,14 @@ ${componentName}: ${componentName};
4962
fs.mkdirSync(typeDir)
5063
}
5164
fs.writeFileSync(typePath, `${`
52-
import { VNodeProps, AllowedComponentProps, ComponentCustomProps } from "@vue/runtime-core";
65+
import { PublicProps } from "vue";
5366
export * as cheetahGrid from 'cheetah-grid'
54-
// type VueInstance = ComponentPublicInstance
55-
56-
/* @see https://unpkg.com/browse/[email protected]/dist/types/ts-helpers.d.ts */
57-
// https://github.com/vuejs/vue-next/blob/d84d5ecdbdf709570122175d6565bb61fae877f2/packages/runtime-core/src/apiDefineComponent.ts#L29-L31
58-
// TODO: This can be imported from vue directly once this PR gets merged: https://github.com/vuejs/vue-next/pull/2403
59-
type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps;
60-
61-
// Can't use \`DefineComponent\` because of the false prop inferring behavior, it doesn't pick up the required types when an interface is passed
62-
// This PR will probably solve the problem as it moves the prop inferring behavior to \`defineComponent\` function: https://github.com/vuejs/vue-next/pull/4465
63-
// GlobalComponentConstructor helper is kind of like the ComponentConstructor type helper, but simpler and keeps the Volar errors simpler,
64-
// and also similar to the usage in official Vue packages: https://github.com/vuejs/vue-next/blob/d84d5ecdbdf709570122175d6565bb61fae877f2/packages/runtime-core/src/components/BaseTransition.ts#L258-L264 or https://github.com/vuejs/vue-router-next/blob/5dd5f47515186ce34efb9118dda5aad0bb773439/src/RouterView.ts#L160-L172 etc.
65-
// TODO: This can be replaced with \`DefineComponent\` once this PR gets merged: https://github.com/vuejs/vue-next/pull/4465
66-
type GlobalComponentConstructor<Props = {}, Slots = {}> = {
67+
68+
type ComponentConstructor<Props = {}, Methods = {}, Slots = {}> = {
6769
new (): {
6870
$props: PublicProps & Props
6971
$slots: Slots
70-
}
72+
} & Methods
7173
}
7274
7375
${componentTypes.join('\n')}

0 commit comments

Comments
 (0)