halfnelson / nativescript-source-to-jsx-def

Walk nativescript source to generate JSX types for `svelte-type-checker-vscode`
Other
4 stars 1 forks source link

Auto-generation of the implementation for plugins #20

Open shirakaba opened 4 years ago

shirakaba commented 4 years ago

Background

I've sketched out a proof of concept of what I had in mind, on shirakaba/autogenerate-plugins-implementation. It has opened up a few rabbit holes.

Desired output

What I'm aiming for is to produce text like this (example here is auto-generation of RadSideDrawer, which I've drafted out roughly on my branch):

import { registerElement, NSVElement, NSVViewFlags } from "react-nativescript";

registerElement(
    'radSideDrawer',
    () => require('nativescript-ui-sidedrawer')["RadSideDrawer"],
    {
      nodeOps: {
        insert(child: NSVElement, parent: NSVElement, atIndex?: number): void {
          // You need to fill this in!
        },
        remove(child: NSVElement, parent: NSVElement): void {
          // You need to fill this in!
        }
      }
    }
);

To clarify: I've modelled my registerElement exactly after NativeScript Vue's.

The issue here is the // You need to fill this in!. It would be great if somehow the implementation could be automatically generated.

Types of plugins

There are several cases of plugin to handle:

  1. Ones that extend ContentView (easy)
  2. Ones that extend LayoutBase (easy)
  3. None-visual plugins (don't want to think about this just yet)
  4. Ones that extend TextBase (NativeScript Vue doesn't handle this as a special case yet, so I think this might involve revisiting the DOM model)
  5. Ones that extend View (totally irregular)

Inferring DOM operations

My main worry is about that last category.

1:1 relationships

I wonder if it's possible to automatically handle cases such as these interfaces:

// index.d.ts
export type RadSideDrawerAttributes = ViewAttributes & {
    // ...
    drawerContent?: string | View;
    // ...
    mainContent?: string | View;
    // ...
}

If a property supports type View, then it may be a basic setter relationship for the insert() and remove() operations. These would use something like parentNodeKey or nodeRole or whatever the renderer has decided to use to distinguish the mainContent role from the drawerContent role, but either way, they'd be auto-generatable.

1:N relationships

There are also one-to-many relationships that might be possible to infer and handle automatically, again with some dependency upon an implicitly present nodeRole property:

// ui/text-base/formatted-string.ts
export type FormattedStringAttributes = ViewBaseAttributes & {
    // ...
    spans?: ObservableArray<Span>;
    // ...
}

Too much effort?

It sounds tough to make something robust out of all this. There's a great temptation to simply pass all the work of implementing the DOM operations onto the plugins authors, but I fear that such an attitude would leave Svelte Native and React NativeScript, as they are today, with a still-barren plugins landscape due to lack of community will to fill in the implementation for all the plugins.

It would be great if somehow the implementation could reliably be inferred just by inspecting the typings, even if it only worked in 80% of cases (as 80% of the plugins marketplace is still a great haul).

Worth chatting over the feasibility of it, however.