Saltarelle / SaltarelleCompiler

C# to JavaScript compiler – Now http://bridge.net
http://saltarelle-compiler.com
Other
297 stars 74 forks source link

Strategy for using JS frameworks: Ext JS #196

Open xersoft opened 11 years ago

xersoft commented 11 years ago

This isn’t an enhancement request and really should be posted as a question somewhere. I wasn’t able to find such a location so here goes. (If there is a better place please direct me to it.)

Are there any ideas or strategies for using the class system developed in Extjs 4.0 with Saltarelle? The problem is that they define their classes by calling a method, including a defining object to build the class structure with.

Calling a method in a framework using Saltarelle isn’t an issue. But using the inheritance system that is built up with the Ext 4.0 class system is.

Here is a link that describes how their system works. http://docs.sencha.com/extjs/4.2.0/#!/guide/class_system

any thoughts on how to handle this type of thing? Is it even possible to maintain a strictly typed structure (C#) and use Extjs?

Mostly just interested in some thoughts.

erik-kallen commented 11 years ago

I have used Dojo (which is not the same, but I think is similar) myself in the past, and I absolutely think it is possible to use those systems with static typing (and it actually being a rather big advantage of doing so). It has actually been a design goal in the compiler to enable this.

It certainly is possible (well; maybe not today, but in theory and I am absolutely willing to make any required changes) to use the pluggable compilation process to specify that some classes (either when the classes or the assembly has a certain attribute, or if the class derives from a certain class) should be instantiated via Ext.define() rather than ss.registerType().

A problem, though, is that we might need to model multiple inheritance in some way (if Ext doesn't support multiple inheritance, just ignore this).

Finally, we would need an import library, and I guess Ext has some structured documentation that can be used to generate this code automatically.

erik-kallen commented 11 years ago

After looking a little at Ext, it seems that we do not need to worry about multiple inheritance.

I haven't been able to find structured documentation, though, but looking at their API docs it's obvious that they have it, so it might be possible to ask them if they can supply it.

xersoft commented 11 years ago

Hi, thanks for the reply. I agree that some classes would need to be defined using the ‘platform’ method for defining classes instead of ss.registerType(). That would certainly go a long way to easing into using a library like ExtJs. I have been racking my brain trying to find a way to call the method in ExtJs to define a class and perhaps just pass in an object to define the various parts of the class, and I think I could do that today with the Compiler you have built, but I’d lose all typing and thus one of the core reasons for using the compiler.

You had mentioned adding an attribute to the class to allow another platform to do the creation of the class definition eg. Ext.define(… How would you handle the instantiation of the objects? In the ExtJs world they have a method: Ext.create(‘name’) which does the creation. Would you have another attribute that would allow an override to instantiation of classes?

ExtJs does support multiple inheritance and they call them “Inherited Mixins” Here is an example (look on the far right) http://docs.sencha.com/extjs/4.2.0/#!/api/Ext.button.Button

I think we could just use interfaces in the c# world. (Unless I am misunderstanding what you mean)

I am excited by your interest. Is there anything I can do to help move this forward? I would be willing to test and write example ExtJs projects.

xersoft commented 11 years ago

I am not sure if directly creating an import library from http://docs.sencha.com/extjs/4.2.0/#!/api is possible but it is somewhat structured. I imagine I’d just hand crank my own if enough attributes were available to get over the initial hump of incompatibility. That would be a good way to start testing at least. I hand cranked a partial library for http://www.greensock.com/ and it worked awesome!

xersoft commented 11 years ago

Also, although I haven't used this, it might provide some help for definition. http://docs.sencha.com/extjs/4.2.0/#!/guide/command_compiler_meta

erik-kallen commented 11 years ago

Regarding the first link, yes I think it's structured but annoying to parse. I think it is worth a shot to ask if Sencha can make available some more machine-friendly format.

I think there are enough attributes available to create a good model for using Ext. Defining own classes in the Ext universe will require a plugin, though (and also compiler changes because I don't think the IOOPEmulator interface is really useful today but I prefer not trying to generalize stuff until I have a user of the generalization).

Regarding the compiler meta options, I don't think it's helpful for this, the article you linked contains no indication that it can be used to extract the required metadata (eg. parameter types and return value types for methods).

erik-kallen commented 11 years ago

Or, perhaps they are generating the docs directly from the doc-comments in the source, eg. http://docs.sencha.com/extjs/4.2.0/source/Ext-more.html#Ext-property-isIE10m. We could do that too, the compiler has a JS parser (although it will probably need to be slightly modified for this use case as it needs to insert doc-comments into the parse tree).

heiskanen commented 10 years ago

Hi,

I'v been using ExtJS with Script# library for years now by creating import library from ExtJS docs and overriding Script#:s registerClass function so that if class is extending from ExtJS class then it uses Ext.define to define class.

This works quite well allthough it has some quirks and now that Script# uses amd-pattern I cannot use this anymore so now I'm lookin for alternatives for Script# and I found SaltarelleCompiler (not yet tried it but I will in few days).

So, I was wondering would it be possible to get compiler to directly create ExtJS class definition if it recognizes that class is ExtJS class (maybe decorated with class attribute [ExtClass] or something else.

theoutlander commented 10 years ago

The docs are auto generated. I tried to replicate that for Script# but turned out that it was a bit more work than I anticipated. For ExtJS, generating them automatically is the only way as the library is way too large to maintain. There is some code out there that generates the SharpKit stubs and might be reusable, but isn't exactly trivial.

heiskanen commented 10 years ago

Ok, issue is not to create stubs or imported library from extjs (this I have been creating for years now). What I ment and what the issue is that when I'm extending from classes that exist in ExtJS library like this

public class LoginCompanyStore : Ext.data.Store

then compiler could produce ExtJS class definition like this:

Ext.define('ClassLibrary1.LoginCompanyStore', { extend: 'Ext.store.Store'....

instead of this:

ss.initClass($ClassLibrary1_LoginCompanyStore, $asm, {}....

Sorry for not making this quite clear on my first comment.

erik-kallen commented 10 years ago

This is now possible by providing a custom implementation if IOOPEmulator in your import library. Please see the discussion in #263

heiskanen commented 10 years ago

Ok, good to know. Any pointers how to get started with this?

erik-kallen commented 10 years ago

Look at the Knockout library (which does provide a custom MetadataImporter, but does not have any use for an OOPEmulator) and create a class like the example in #263. Put your code on GitHub and ask me if you need help.

erik-kallen commented 10 years ago

And, speaking of the auto-generation, I think (though I'm not sure) that they use a slightly modified variant of JSDoc to auto-generate their docs.

If someone has way too much free time, having a converter to convert JSDoc-annotated to C# wrappers automatically would probably be very useful

heiskanen commented 10 years ago

Hmmm, sorry, but I just don't get this.

So I create OOPEmulator to my import library just like in that example and build my library to dll. Then I add reference to that dll to my js project and then what? How do I get my classes that inherit from classes in import library to have different js init code compiled?

I did tried this with that JayData project (builded it and referenced my project to that dll) but I could not figured out how to get js like $data.Entity.extend... out, I just got ss.initClass(...

heiskanen commented 10 years ago

Now I got it, I'll have to link .Plugin dll as embedded resource to my import library. Now I just have to figure out how to generate inits for classes (functions etc).

heiskanen commented 10 years ago

Hi again, is there any documentation about creating custom implementation of IOOPEmulator? Or should I just copy implementation from CoreLib.Plubin.OOPEmulator (and assosiated classes) and start modifying that with trial and error method?

erik-kallen commented 10 years ago

Unfortunately, there is no documentation like that, but check out https://github.com/marwijn/SaltarelleJayData/blob/develop/JayData.Plugin/JayDataOOPEmulator.cs

heiskanen commented 10 years ago

Ok, slowly getting somewhere. Now I know howto create proper class initialization for extjs classes but, now the problem is that how can I rewrite class constructors?

Ie. now if I have csharp class like this:

public class TestClass
{
    private int PrivateField = 10;
    public int PublicField = 20;

    public TestClass()
    {
        //Do something...
    }
}

compiler outputs it like this:

var $ExtSharp_Test_TestClass = function() {
    this.$privateField = 10;
    this.publicField = 20;
    //Do something...
};

and I would like it to be in class init like this:

var $ExtSharp_Test_TestClass = Ext.define('ExtSharp.Test.TestClass', {
    $privateField: 10,
    publicField, 20,
    constructor: function() {
        //Do something...
    }
};

How can I accomplish this?

erik-kallen commented 10 years ago

That is a good question. I will need to think about this and get back to you.

erik-kallen commented 10 years ago

I'm leaning towards adding a ShouldBeInitialized boolean property on FieldScriptSemantics. This would require you to implement a custom MetadataImporter that overrides the base behavior for fields and clears this flag, as well as iterating through all fields in the OOPEmulator to add them to the creation object. What do you think?

heiskanen commented 10 years ago

Ok, that could be one but I would have to rewrite constructor code allso 'cause extjs uses this.callParent(arguments) to call parent function. I'm thinking that I could just skip constructors alltogether in my OOPEmulator and just iterate fields and add them as you succested. Constructor in extjs classes should be "constructor" member anyway so if I want to define constructor in my extjs inherited class I should write it like "protected void constructor() { }" in CSharp. BTW, is there any way to check that any of class's parents is class in my ExtJS stub library? I'm trying to build some autodetection logic to my OOPEmulator so that I would't have to decorate class with any attributes.

marwijn commented 10 years ago

Hello Heiskanen,

It seems that we are both struggling with the same issues. If you take a look at my code, please be aware that I'm changing all the time and that any current version might be very very wrong. If you have anything (remotely) working can you send a link so that I can learn ?

Regards, Marwijn.

heiskanen commented 10 years ago

Hi Marwijn,

I'm actually getting really close to get this working (for me at least). Unfortunately I don't have any github repository (yet) for what I could give link to you but, until then I will gladdly share my thoughts, just let me know where I can help.

Regards, Heiskanen

heiskanen commented 10 years ago

Hi again,

Is there any way to order created javascript so that "base" class definitions would be first and definitions for classes that inherits from them would be later in generated javascript.

Ie,

public class A : B {

}

public class B {

}

would always generate javascript in this order:

Ext.define('B', { config... }; Ext.define('A', { extend: 'B', config...}

Regards, Heiskanen

erik-kallen commented 10 years ago

Yes, that's what the DependentOnTypes member of TypeOOPEmulationPhase is for.