Skip to content

Commit

Permalink
Generated mat-form-field but it's very wonky
Browse files Browse the repository at this point in the history
  • Loading branch information
wwwillchen committed Dec 16, 2023
1 parent 1d07a0e commit a000c92
Show file tree
Hide file tree
Showing 19 changed files with 332 additions and 10 deletions.
22 changes: 22 additions & 0 deletions generator/output_data/form_field.binarypb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

`

form_field" MatFormField*mat-form-field22
@angular/material/form-fieldMatFormFieldModule!
hideRequiredMarkerboolean9
color"
primary
accent
warnprimary ThemePalette6

floatLabel
always
autoalwaysFloatLabelType=

appearance
fill
outlinefillMatFormFieldAppearance=
subscriptSizing
fixed
dynamicfixedSubscriptSizing
hintLabelstring
84 changes: 84 additions & 0 deletions generator/output_data/form_field.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"input": {
"name": "form_field",
"targetClass": "MatFormField",
"hasContent": true,
"elementName": "mat-form-field",
"tsFilename": "",
"directiveNamesList": [],
"nativeEventsList": [],
"skipPropertyNamesList": [],
"ngModule": {
"importPath": "@angular/material/form-field",
"moduleName": "MatFormFieldModule",
"otherSymbolsList": []
}
},
"inputPropsList": [
{
"name": "hideRequiredMarker",
"alias": "",
"type": {
"simpleType": 2
},
"debugType": "boolean"
},
{
"name": "color",
"alias": "",
"type": {
"simpleType": 0,
"stringLiterals": {
"stringLiteralList": ["primary", "accent", "warn"],
"defaultValue": "primary"
}
},
"debugType": "ThemePalette"
},
{
"name": "floatLabel",
"alias": "",
"type": {
"simpleType": 0,
"stringLiterals": {
"stringLiteralList": ["always", "auto"],
"defaultValue": "always"
}
},
"debugType": "FloatLabelType"
},
{
"name": "appearance",
"alias": "",
"type": {
"simpleType": 0,
"stringLiterals": {
"stringLiteralList": ["fill", "outline"],
"defaultValue": "fill"
}
},
"debugType": "MatFormFieldAppearance"
},
{
"name": "subscriptSizing",
"alias": "",
"type": {
"simpleType": 0,
"stringLiterals": {
"stringLiteralList": ["fixed", "dynamic"],
"defaultValue": "fixed"
}
},
"debugType": "SubscriptSizing"
},
{
"name": "hintLabel",
"alias": "",
"type": {
"simpleType": 1
},
"debugType": "string"
}
],
"outputPropsList": []
}
65 changes: 55 additions & 10 deletions generator/spec_generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,21 @@ inputSpecInput.setElementName('input');
inputSpecInput.addDirectiveNames('matInput');
inputSpecInput.addSkipPropertyNames('errorStateMatcher');

const formFieldSpecInput = (() => {
const i = new pb.ComponentSpecInput();
i.setName('form_field');
i.setHasContent(true);
return i;
})();

const SYSTEM_IMPORT_PREFIX = '@angular/material/';
const SYSTEM_PREFIX = 'Mat';
const SPEC_INPUTS = [inputSpecInput, buttonSpecInput, checkboxSpecInput].map(
preprocessSpecInput,
);
const SPEC_INPUTS = [
inputSpecInput,
buttonSpecInput,
checkboxSpecInput,
formFieldSpecInput,
].map(preprocessSpecInput);

function preprocessSpecInput(
input: pb.ComponentSpecInput,
Expand Down Expand Up @@ -70,10 +80,23 @@ interface Issue {
}

class NgParser {
initDefaultMap(): Map<string, pb.XType> {
const map = new Map<string, pb.XType>();

// Hard to infer ThemePalette since it's in a central file.
const xType = new pb.XType();
const sl = new pb.StringLiterals();
sl.setStringLiteralList(['primary', 'accent', 'warn']);
sl.setDefaultValue('primary');
xType.setStringLiterals(sl);
map.set('ThemePalette', xType);
return map;
}
proto: pb.ComponentSpec;
private issues: Issue[] = [];
private currentNode!: ts.Node;
sourceFile!: ts.SourceFile;
private typeAliasMap: Map<string, pb.XType> = this.initDefaultMap();
constructor(
private readonly input: pb.ComponentSpecInput,
filePath: string,
Expand All @@ -91,7 +114,11 @@ class NgParser {
ts.ScriptTarget.Latest,
true, // setParentNodes flag
);

for (const statement of this.sourceFile.statements) {
if (ts.isTypeAliasDeclaration(statement)) {
this.collectTypeAliases(statement);
}
}
this.sourceFile.statements.find((s) => {
if (ts.isClassDeclaration(s)) {
if (s.name?.escapedText === this.input.getTargetClass()) {
Expand All @@ -100,6 +127,13 @@ class NgParser {
}
});
}
collectTypeAliases(statement: ts.TypeAliasDeclaration) {
const name = statement.name.getText();
if (statement.type) {
const xType = this.getType(statement.type);
this.typeAliasMap.set(name, xType);
}
}

logIssue(msg: string, context?: object | string) {
this.issues.push({msg, context, node: this.currentNode?.getText()});
Expand Down Expand Up @@ -134,14 +168,13 @@ class NgParser {
}
return false;
} else {
console.log(FgGreen, 'Validation succeeded!');
console.log(FgGreen, 'Validation succeeded!', Reset);
return true;
}
}

processClass(cls: ts.ClassDeclaration) {
for (const member of cls.members) {
console.log('member', member.getText());
if (ts.isGetAccessor(member) && member.modifiers) {
for (const modifier of member.modifiers) {
if (
Expand Down Expand Up @@ -313,7 +346,12 @@ class NgParser {
if (simpleTypes[0]) {
typeProto.setSimpleType(simpleTypes[0]);
} else {
this.logIssue('Unhandled simple type', {type: simpleTypes[0]});
// Maybe it's a type alias
if (this.typeAliasMap.has(text)) {
return this.typeAliasMap.get(text)!;
} else {
this.logIssue('Unhandled single type', {type: text});
}
}
return typeProto;
} else {
Expand All @@ -322,7 +360,13 @@ class NgParser {
const typeProto = new pb.XType();
const sl = new pb.StringLiterals();
sl.setStringLiteralList(stringLiterals);
sl.setDefaultValue(this.stripQuotes(initializer!.getText()));
if (!initializer) {
// If there's no initializer, then we just pick the first value (somewhat arbitrary, but
// Angular Material seemes to default to it).
sl.setDefaultValue(stringLiterals[0]);
} else {
sl.setDefaultValue(this.stripQuotes(initializer.getText()));
}
typeProto.setStringLiterals(sl);
return typeProto;
}
Expand All @@ -344,7 +388,8 @@ class NgParser {
stripQuotes(t: string): string {
// Strip off quotes (but sanity check first)
if (t[0] !== "'" && t[t.length - 1] !== "'") {
this.logIssue('Unexpected type');
this.logIssue('Unexpected type', {string: t});
throw new Error('unexpected type=' + t);
return '<issue>';
}
return t.slice(1, -1);
Expand Down Expand Up @@ -379,7 +424,7 @@ function main() {

const parser = new NgParser(specInput, inputFilePath);

console.log(JSON.stringify(parser.proto.toObject(), null, 2));
// console.log(JSON.stringify(parser.proto.toObject(), null, 2));

if (parser.validate() && workspaceRoot) {
const out_path = path.join(workspaceRoot, 'generator', 'output_data');
Expand Down
1 change: 1 addition & 0 deletions mesop/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ py_library(
],
deps = [
# REF(//scripts/scaffold_component.py):insert_component_import
"//mesop/components/form_field:py",
"//mesop/components/input:py",
"//mesop/components/markdown:py",
"//mesop/components/text_input:py",
Expand Down
1 change: 1 addition & 0 deletions mesop/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from mesop.components.checkbox.checkbox import (
checkbox as checkbox,
)
from mesop.components.form_field.form_field import form_field as form_field
from mesop.components.input.input import input as input
from mesop.components.markdown.markdown import markdown as markdown
from mesop.components.text.text import text as text
Expand Down
9 changes: 9 additions & 0 deletions mesop/components/form_field/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
load("//mesop/components:defs.bzl", "mesop_component")

package(
default_visibility = ["//build_defs:mesop_internal"],
)

mesop_component(
name = "form_field",
)
Empty file.
13 changes: 13 additions & 0 deletions mesop/components/form_field/e2e/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
load("//build_defs:defaults.bzl", "py_library")

package(
default_visibility = ["//build_defs:mesop_internal"],
)

py_library(
name = "e2e",
srcs = glob(["*.py"]),
deps = [
"//mesop",
],
)
1 change: 1 addition & 0 deletions mesop/components/form_field/e2e/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import form_field_app as form_field_app
10 changes: 10 additions & 0 deletions mesop/components/form_field/e2e/form_field_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import mesop as me


@me.page(path="/components/form_field/e2e/form_field_app")
def app():
me.text(text="Hello, World!")
me.input()
with me.form_field():
me.input()
me.text(text="Another")
8 changes: 8 additions & 0 deletions mesop/components/form_field/e2e/form_field_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {test, expect} from '@playwright/test';

test('test', async ({page}) => {
await page.goto('/components/form_field/e2e/form_field_app');
expect(await page.getByText('Hello, world!').textContent()).toContain(
'Hello, world!',
);
});
14 changes: 14 additions & 0 deletions mesop/components/form_field/form_field.ng.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<mat-form-field
[hideRequiredMarker]="config().getHideRequiredMarker()"
[color]="getColor()"
[floatLabel]="getFloatLabel()"
[appearance]="getAppearance()"
[subscriptSizing]="getSubscriptSizing()"
[hintLabel]="config().getHintLabel()"
>
<!-- <div>
</div> -->
<ng-content></ng-content>
<input matInput hidden />
</mat-form-field>
13 changes: 13 additions & 0 deletions mesop/components/form_field/form_field.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

syntax = "proto3";

package mesop.components.form_field;

message FormFieldType {
bool hide_required_marker = 1;
string color = 2;
string float_label = 3;
string appearance = 4;
string subscript_sizing = 5;
string hint_label = 6;
}
36 changes: 36 additions & 0 deletions mesop/components/form_field/form_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from typing import Literal

from pydantic import validate_arguments

import mesop.components.form_field.form_field_pb2 as form_field_pb
from mesop.component_helpers import (
insert_composite_component,
)


@validate_arguments
def form_field(
*,
key: str | None = None,
hide_required_marker: bool = False,
color: Literal["primary", "accent", "warn"] = "primary",
float_label: Literal["always", "auto"] = "always",
appearance: Literal["fill", "outline"] = "fill",
subscript_sizing: Literal["fixed", "dynamic"] = "fixed",
hint_label: str = "",
):
"""
TODO_doc_string
"""
return insert_composite_component(
key=key,
type_name="form_field",
proto=form_field_pb.FormFieldType(
hide_required_marker=hide_required_marker,
color=color,
float_label=float_label,
appearance=appearance,
subscript_sizing=subscript_sizing,
hint_label=hint_label,
),
)
Loading

0 comments on commit a000c92

Please sign in to comment.