You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by hu...@apache.org on 2023/01/26 17:47:39 UTC

[superset] 01/01: first iteration

This is an automated email from the ASF dual-hosted git repository.

hugh pushed a commit to branch api-contracts
in repository https://gitbox.apache.org/repos/asf/superset.git

commit c0381b756dc1f84bd172a7288228d54b7bebe3b0
Author: hughhhh <hu...@gmail.com>
AuthorDate: Thu Jan 26 19:47:19 2023 +0200

    first iteration
---
 api_to_ts.py           | 12 +++++++
 output.ts              |  6 ++++
 superset/typemallow.py | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 104 insertions(+)

diff --git a/api_to_ts.py b/api_to_ts.py
new file mode 100644
index 0000000000..6a5516b027
--- /dev/null
+++ b/api_to_ts.py
@@ -0,0 +1,12 @@
+from superset import typemallow as tm
+from marshmallow import Schema, fields
+
+
+@tm.ts_interface()
+class Foo(Schema):
+    some_field_one = fields.Str(required=True)
+    another_field = fields.Date()
+    one_more_field = fields.Integer()
+
+
+tm.generate_ts('./output.ts')
\ No newline at end of file
diff --git a/output.ts b/output.ts
new file mode 100644
index 0000000000..bdea128497
--- /dev/null
+++ b/output.ts
@@ -0,0 +1,6 @@
+export interface Foo {
+	some_field_one?: string;
+	another_field?: any;
+	one_more_field?: number;
+}
+
diff --git a/superset/typemallow.py b/superset/typemallow.py
new file mode 100644
index 0000000000..507874885f
--- /dev/null
+++ b/superset/typemallow.py
@@ -0,0 +1,86 @@
+from marshmallow import Schema, fields
+
+mappings = {
+    fields.Bool: 'boolean',
+    fields.Boolean: 'boolean',
+    fields.Constant: 'any',
+    fields.DateTime: 'Date',
+    fields.Decimal: 'number',
+    fields.Dict: 'object',
+    fields.Email: 'string',
+    fields.Field: 'any',
+    fields.Float: 'number',
+    fields.Function: 'any',
+    fields.Int: 'number',
+    fields.Integer: 'number',
+    fields.List: 'any[]',
+    fields.Mapping: 'any',
+    fields.Method: 'any',
+    fields.Number: 'number',
+    fields.Raw: 'any',
+    fields.Str: 'string',
+    fields.String: 'string',
+    fields.TimeDelta: 'any',
+    fields.Url: 'string',
+    fields.UUID: 'string',
+}
+
+__schemas = dict()
+
+def ts_interface(context='default'):
+    '''
+    Any valid Marshmallow schemas with this class decorator will 
+    be added to a list in a dictionary. An optional parameter: 'context'
+    may be provided, which will create separate dictionary keys per context.
+    Otherwise, all values will be inserted into a list with a key of 'default'.
+    e.g.
+    @ts_interface(context='internal')
+    class Foo(Schema):
+        first_field = fields.Integer()
+    '''
+    def decorator(cls):
+        if issubclass(cls, Schema):
+            if not context in __schemas:
+                __schemas[context] = []
+            __schemas[context].append(cls)
+        return cls
+    return decorator
+
+
+def __get_ts_interface(schema):
+    '''
+    Generates and returns a Typescript Interface by iterating
+    through the declared Marshmallow fields of the Marshmallow Schema class
+    passed in as a parameter, and mapping them to the appropriate Typescript
+    data type.
+    '''
+    name = schema.__name__.replace('Schema', '')
+    ts_fields = []
+    for key, value in schema._declared_fields.items():
+        if isinstance(value, fields.Nested):
+            ts_type = value.nested.__name__.replace('Schema', '')
+            if value.many:
+                ts_type += '[]'
+        else:
+            ts_type = mappings.get(type(value), 'any')
+
+        ts_fields.append(
+            f'\t{key}: {ts_type};'
+        )
+    ts_fields = '\n'.join(ts_fields)
+    return f'export interface {name} {{\n{ts_fields}\n}}\n\n'
+
+
+def generate_ts(output_path, context='default'):
+    '''
+    When this function is called, a Typescript interface will be generated
+    for each Marshmallow schema in the schemas dictionary, depending on the
+    optional context parameter provided. If the parameter is ignored, all
+    schemas in the default value, 'default' will be iterated over and a list
+    of Typescript interfaces will be returned via a list comprehension.
+    
+    The Typescript interfaces will then be outputted to the file provided.
+    '''
+    with open(output_path, 'w') as output_file:
+        interfaces = [__get_ts_interface(schema) for schema in __schemas[context]]
+        output_file.write(''.join(interfaces))
\ No newline at end of file