Generate from Vega-lite Spec
lan-lyu opened this issue · 4 comments
I used type checker and AST node to parse from vega-lite/src/spec/index.ts, and begin from this:
export type TopLevelSpec =
| TopLevelUnitSpec<Field>
| TopLevelFacetSpec
| TopLevel<LayerSpec<Field>>
| TopLevel<RepeatSpec>
| TopLevel<GenericConcatSpec<NonNormalizedSpec>>
| TopLevel<GenericVConcatSpec<NonNormalizedSpec>>
| TopLevel<GenericHConcatSpec<NonNormalizedSpec>>;
Now it can parse the type inheritance like this (full text)
############### TopLevelUnitSpec<Field> ###############
####### TopLevelUnitSpec<Field> #######
- TopLevelUnitSpec<Field>
-- GenericUnitSpec<FacetedCompositeEncoding<Field>, AnyMark, TopLevelParameter>
-- ResolveMixins
-- GenericCompositionLayout
-- FrameMixins<any>
-- TopLevelProperties<any>
-- { $schema?: string; config?: Config<any>; datasets?: Datasets; usermeta?: Dict<unknown>; }
-- DataMixins
####### Field #######
- Field
-- string
-- RepeatRef
and get properties in these types (full text)
############### TopLevelUnitSpec<Field> ###############
####### TopLevelUnitSpec<Field> #######
### mark ###
### encoding ###
### projection ###
### params ###
### title ###
### name ###
### description ###
### data ###
### transform ###
### resolve ###
### align ###
### center ###
### spacing ###
### bounds ###
### view ###
### width ###
### height ###
### background ###
### padding ###
### autosize ###
### $schema ###
### config ###
### datasets ###
### usermeta ###
####### Field #######
### toString ###
### valueOf ###
### repeat ###
And types in each property such as mark (full text)
############### TopLevelUnitSpec<Field> ###############
####### TopLevelUnitSpec<Field> #######
### mark ###
AnyMark
"boxplot"
"errorbar"
"errorband"
BoxPlotDef
ErrorBarDef
ErrorBandDef
"arc"
"area"
"bar"
"image"
"line"
"point"
"rect"
"rule"
"text"
"tick"
"trail"
"circle"
"square"
"geoshape"
MarkDef<"arc" | "area" | "bar" | "image" | "line" | "point" | "rect" | "rule" | "text" | "tick" | "trail" | "circle" | "square" | "geoshape", any>
The code is in
Vega-lite-api is using FacetedEncoding
for generating encoding channels. While FacetedEncoding
is in json-schema, it's not in vega-lite src types.
Is it because this json-schema is not updated with the types? If not, how does json-schema-generator come up with FacetedEncoding
? @domoritz
There is a rename step because the names from the generator were not what we wanted: https://github.com/vega/vega-lite/blob/main/scripts/rename-schema.sh
This week's update:
Auto-generate files from typescript types
The generation logic is from vega-lite-api constants. When I meet a 'TopLevelUnitSpec', I generate mark
and data
.
mark: 'TopLevelUnitSpec',
layer: 'TopLevelLayerSpec',
concat: 'TopLevelConcatSpec',
hconcat: 'TopLevelHConcatSpec',
vconcat: 'TopLevelVConcatSpec',
_repeat: 'TopLevelRepeatSpec',
_facet: 'TopLevelFacetSpec',
spec: 'TopLevelSpec',
data: 'TopLevelUnitSpec',
In this way, as long as we have a well-defined constant, all codes can be generated. But will that influence the maintainability of the code?
- check if the generation logic is okay
Create Internal Representation (In Process)
Now when generating, the types still have inheritances, for example, boolean | RowCol<boolean>
as shown below.
center(value: boolean | RowCol<boolean>) {
if (arguments.length) {
const obj = copy(this);
set(obj, "center", value);
return obj;
} else {
return get(this, "center");
}
}
To solve this, I plan to have a class that stores the inheritance through children's classes so that we can get the oneLevelType
from children's oneLevelType
.
// internal representation of a type
class VegaLiteType {
name: string;
type: ts.Type;
kind: TypeKind;
children: VegaLiteType[];
oneLevelType: string;
properties?: ts.Type[];
description?: string; //TODO: get descirption and generate documentation
constructor(name: string, type: ts.Type, kind: TypeKind, children: VegaLiteType[]) {
this.name = name;
this.type = type;
this.kind = kind;
this.children = children;
// this.oneLevelType = this.updateOneLevelType();
this.properties = (type as any).properties;
}
generateOneLevelType(): string {
switch (this.kind) {
case TypeKind.Union:
return this.children.map(child => child.generateOneLevelType()).join(" | ");
case TypeKind.Intersection:
return this.children.map(child => child.generateOneLevelType()).join(" & ");
case TypeKind.Literal:
return this.name;
case TypeKind.TypeParameter:
return this.name;
case TypeKind.Other:
return this.name;
}
}
updateOneLevelType(): void {
this.oneLevelType = this.generateOneLevelType();
}
}