Giter Site home page Giter Site logo

ensembleui / ensemble_ts_interpreter Goto Github PK

View Code? Open in Web Editor NEW
29.0 7.0 1.0 354 KB

Javascript ES5 parser and interpreter written entirely in dart.

Home Page: https://ensembleui.com

License: BSD 3-Clause "New" or "Revised" License

Dart 100.00%
dart es5-javascript flutter javascript

ensemble_ts_interpreter's Introduction

(This repo is deprecated. Please use the monorepo Ensemble instead).

This is a javascript ES5 parser and interpreter written entirely in dart.

What it is

  • Primary use case is to let users type in simple js that you want to execute inline. This should be not used as a general replacement for dart in flutter
  • Runs in the same process as your Dart/Flutter code so no need to use the browser's javascript engine. As a result, this is fast.
  • Unlike react native, doesn't require any bridge or have memory issues
  • Supports most common use cases right now such as functions, lists, all primitive types (string, number, arrays, dates) etc.
  • Highly extensible. The context object could be json or any dart object enhanced with the Invokable mixin (see below)

How to use

  • in your pubspec.yaml, add the following line under dependencies -
  ensemble_ts_interpreter:
    git:
      url: https://github.com/EnsembleUI/ensemble_ts_interpreter.git
      ref: master
  • run flutter pub upgrade
  • Simply call the JSInterpreter with the code you want to evaluate while passing it the context.

JSInterpreter.fromCode(code, context).evaluate();

context is the key object here. You can pass json as context (see examples below) or pass an instance of Invokable which could be any Dart object.

Examples

All the examples are in the unit test suite - new_interpreter_tests

Listing some here.

Filter a list

    Map<String, dynamic> context = {
      'items': ['one', 'two', 'three'],
      'nested': [
        {'id': 1, 'label': 'eggs', 'type': ''},
        {'id': 2, 'label': 'strawberry', 'type': 'fruit'},
        {'id': 3, 'label': 'nut'}
      ]
    };

    String code = """
      var flatList = items.filter(function(e) {
        return e != 'two';
      });
      
      var nestedList = nested.filter(function(e) {
        return e['type'] == 'fruit'
      });
    """;
    
    JSInterpreter.fromCode(code, context).evaluate();

Different String functions

    Map<String, dynamic> context = initContext();

    String code = """
        var arr = ['a','b','c','d'];
        var b = arr.at(1);
        var arr2 = arr.concat(['e','f']);
        var f = arr2.find(function (element)  { 
              var rtn = ( element == 'f' )? true : false;
              return rtn;
         });
         var includes = arr2.includes('e');
         var str = arr.join();
         var str2 = arr.join('-');
         var str3 = arr.join('');
         var last = arr2.pop(); 
         var nums = [1,2,3,4,5];
         var sum = nums.reduce(function (value, element) {
            return value + element;
            });
         var reversed = arr.reverse();
        """;

    JSInterpreter.fromCode(code, context).evaluate();

Function Declaration and then calling the functions

  test('functiondeclarationtext', () async {
    String codeToEvaluate = """
      var i = 0;
      var users = [{'name':'Khurram'},{'name':'Mahmood'}];
      updateSalary(users,noArgFunction());
      return manyParms(users[0],noArgFunction()[0],'Hello','How','are','you','today,');
      function noArgFunction() {
        var salaries = [10000,200000];
        salaries[1] = 900000;
        return salaries;
      }
      function updateSalary(users,salaries) {
        users.map(function(user) {
          user['salary'] = salaries[i];
          user['age'] = age;
          i++;
        });
      }
      function manyParms(user,salary,a,b,c,d,e) {
        return a+' '+b+' '+c+' '+d+' '+e+' '+user.name+'. You made \$'+salary;
      }
        
      """;
    Map<String, dynamic> context = initContext();
    dynamic rtnValue = JSInterpreter.fromCode(codeToEvaluate,context).evaluate();
    expect(context['users'][0]['name'],'Khurram');
    expect(context['users'][0]['salary'],10000);
    expect(context['users'][1]['salary'],900000);
    expect(context['users'][1]['age'],3);
    expect(rtnValue,'Hello How are you today, Khurram. You made \$10000');
  });

ensemble_ts_interpreter's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

hussachai

ensemble_ts_interpreter's Issues

No support in JS for setTimeout method

Primary purpose of setTimeout is to introduce a delay in the execution of code. It allows you to schedule a function or expression to be executed after a specific period of time.
Exp Syntax:
function sayHello() {
console.log("Hello, world!");
}
setTimeout(sayHello, 2000); //delayed by 2 seconds

Automatic back button "navigateScreen"

When using the "navigateScreen" action, an automatic back button is generated in the header by default. However, this can be problematic when attempting to create a transparent header. It would be helpful to have a more straightforward method to disable the automatic back button in such scenarios.

Support proper null conversions and unary operators in js

null, 0, "" etc are treated as false when a ! operator is applied to them.

var b;
if ( !b ) //should return true, same for when b is 0 or empty string
b = 3;
if ( b ) //should return true

also support other unary operators like ~, -, + etc.

Support all String methods in js

support -

trim
trimStart
trimEnd
localeCompare - does comparison without locale
repeat
search
slice
substr

these methods work exactly like js String. For reference, see this

Make function arguments optional

currently the interpreter throws exception if the arguments passed to the function are different in number than the parameters defined on the function -

      var f = function(a,b) {
        return a+(b || 0);
      }
      var a = f(1);
      var b = f(1,2);
      var c = f(1,2,3);

will fail today but is valid js.

This ticket is to support this.

For in loop issue - the iterated var needs to be defined before the loop

Following will throw an exception as person is undefined. It should work properly.

      var i =0;
      var p = 'Khurram'; 
      for ( var person in people ) {
        if ( i == 1 ) {
          continue;
        }      
        people[person]['last_name'] += people[person]['first_name'];
        console.log(people[person].first_name);
        i++;
        if ( i == 2 ) {
          p = person;
          break;
        }
      }
      return p;

Flutter projects fail do build due to incompatible dependencies

After adding

  ensemble_ts_interpreter:
    git:
      url: https://github.com/EnsembleUI/ensemble_ts_interpreter.git
      ref: master

to pubspec.yaml a broken dependency - package_info_plus is being added.

$ flutter pub deps
|-- ensemble_ts_interpreter 1.0.0+1
[...]
|   |-- json_dynamic_widget 3.1.1+1
|   |   |-- automated_testing_framework 3.2.3
[...]
|   |   |   |-- package_info_plus 1.4.3+1
|   |   |   |   |-- package_info_plus_linux 1.0.5

in this file: C:\Users\user\AppData\Local\Pub\Cache\hosted\pub.dev\package_info_plus_windows-2.1.0\lib\src\file_version_info.dart on lines 11 - 17 there is a broken part of code:

class _LANGANDCODEPAGE extends Struct {
  @Uint16()
  external int? wLanguage;

  @Uint16()
  external int? wCodePage;
}
$ flutter run --device-id windows
Launching lib\main.dart on Windows in debug mode...
../../../../AppData/Local/Pub/Cache/hosted/pub.dev/package_info_plus_windows-2.1.0/lib/src/file_version_info.dart(13,17): error G99FC7582: Field 'wLanguage' cannot be nullable or have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct` or `Union`. [C:\Users\user\Documents\....\build\windows\flutter\flutter_assemble.vcxproj]
../../../../AppData/Local/Pub/Cache/hosted/pub.dev/package_info_plus_windows-2.1.0/lib/src/file_version_info.dart(16,17): error G99FC7582: Field 'wCodePage' cannot be nullable or have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct` or `Union`. [C:\Users\user\Documents\....\build\windows\flutter\flutter_assemble.vcxproj]

After patching the file_version_info.dart to use int instead of int?

class _LANGANDCODEPAGE extends Struct {
  @Uint16()
  external int wLanguage;

  @Uint16()
  external int wCodePage;
}

The app compiles fine.

Updating to version 3.0.0 of package_info_plus_windows still have the same Struct with int? so it may not fix the issue.

$ flutter doctor -v
[√] Flutter (Channel beta, 3.10.0-1.4.pre, on Microsoft Windows [Version 10.0.22621.525], locale en-GB)
    • Flutter version 3.10.0-1.4.pre on channel beta at C:\src\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision a14a4eac61 (6 days ago), 2023-04-26 12:54:31 +0700
    • Engine revision f7ac42e8a2
    • Dart version 3.0.0 (build 3.0.0-417.3.beta)
    • DevTools version 2.23.1

[√] Windows Version (Installed version of Windows is version 10 or higher)
[...]
[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.5.3)
    • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community
    • Visual Studio Community 2022 version 17.5.33516.290
    • Windows 10 SDK version 10.0.22000.0
[...]
[√] Connected device (3 available)
    • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.22621.525]
[...]
[√] Network resources
    • All expected network resources are available.

• No issues found!

Code Not Saved Properly

I was working on the code yesterday (June 8th, 2023) and wrote a couple functions. I think around 3 to 4 functions. I also wrote code to test out the functions right after in the body of the Tile. It wasn’t working yet, but I was planning to debug after I took break. I saved my code and went to eat food. When I opened the code again later to work on it, it didn’t save any of the functions I wrote, but it saved the code I wrote after to test the functions in the body. When I look in the history it shows no sign of me writing the code for the 3-4 functions, but it shows the code calling the methods I wrote in the body of the Tile and I really don’t know what happened.

This image shows the body of the Tile calling the functions I wrote that didn’t save.
BodyOfTile

At around 7:31pm is when I started implementing my functions I created into the body of the Tile. At 7:50pm all the methods I wanted to test and had created were all in the body of the Tile.
DifferentTimesOfSaves

At 7:31 on line 120 I started to put the functions I created in the body to test out.
StartingToImplementFunctionsInBody

But when I scroll to the bottom of my code none of the new functions I created are shown.
FunctionsNotShownAtFirstSave

At 7:50pm I have put all the new functions I made to test out (lines 120 to 126).
SecondSaveWithAllFunctionsInBody

But again there is no sign of any of my methods looking like they were done/saved at any point.
SecondSaveNoMethodsShownAgain

After running it at 7:50pm I find issues with my method and leave a comment that there is an error to come back and revisit once I’ve had my dinner. I saved it again at 7:51pm.
CommentAddedAfterRunningConsoleLogAndFindingError

But still no sign of my methods ever being saved at any point.
ThirdSaveWithNoSignOfFunctionsSaved

At 10:25pm Ruth made an edit to the GamePlay page, but she commented out some code that had nothing to do with anything I was working on.

Between 7:00pm and 7:03pm I added 2 methods that I ended up deleting shortly after because I figured out a more effective way to write the code (which led to the 3-4 methods that never saved). But the 2 methods I created between 7:00pm and 7:03pm saved and show in the history still.
HistoryShowingSaveOfMethodsThatIDeletedLaterOn

I don't know what happened. I find it interesting that it saved the code I wrote after the methods in the body but not the actual methods itself when I saved them both at the same time.

IDE seems to be in an infinite loop and I can't access or change the code anymore

IDE says unresponsive, the only option I have is to kill the tab. The last bit of code I added is a while loop. A possible cause could be my while loop never terminated and its in an infinite loop.

Programmers can cause silly errors like this and in this situation they aren't able to go back to their apps and edit them in the IDE. There should be a way for the IDE to terminate (either automatically after some time or give the user a way to kill the never ending code from the IDE or using a shortcut key).

Math.round | JS

Math.round is supposed to returns the value of a number rounded to the nearest integer. we mostly use it to round the numbers coming from the api like if its 100.00 or 100.25 we need to show 100

its working on web studio, but not working on build

support js style forEach that can take one or two arguments

current forEach only allow ones argument.

    var tiles = [0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7];
    var indices = [0,1,2,3,4,5,6,7];

    indices.forEach(function(num){
      var temps = [1,2];
      temps.forEach(function(num1){
        var randomIndex = Math.floor(Math.random() * 16);
        console.log('Random Index :' + randomIndex);
        if(tiles[randomIndex] == undefined) {
          tiles[randomIndex] = num;
        }
      });
    });

works but the following doesn't and it should

    var tiles = [0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7];
    var indices = [0,1,2,3,4,5,6,7];

    indices.forEach(function(num, index){
      var temps = [1,2];
      temps.forEach(function(num1,val1){
        var randomIndex = Math.floor(Math.random() * 16);
        console.log('Random Index :' + randomIndex);
        if(tiles[randomIndex] == undefined) {
          tiles[randomIndex] = num;
        }
      });
    });

Resolving dependencies... - from git depends on http ^0.13.4

Hey,

I want to use the package in my project, but unfortunately I am not able 100% to make it my assumed way. Cause I always try to avoid overriding packages version, but due to incompatible versions of the http package over various packages I needed to

dependency_overrides: http: 1.0.0

Is it possible to increase the http package version in the ensemble_ts_interpreter package? Will be also helpful for future usages.

log for context:
Resolving dependencies... Because no versions of swagger_dart_code_generator match >2.11.10 <3.0.0 and swagger_dart_code_generator 2.11.10 depends on http ^1.0.0, swagger_dart_code_generator ^2.11.10 requires http ^1.0.0. And because every version of ensemble_ts_interpreter from git depends on http ^0.13.4, swagger_dart_code_generator ^2.11.10 is incompatible with ensemble_ts_interpreter from git. So, because wellahead_mobile depends on both ensemble_ts_interpreter from git and swagger_dart_code_generator ^2.11.10, version solving failed.

2d arrays are not handled correctly when changing values of the nested array

Thanks to @tanyareuben for finding the issue

function createRandomizedTiles() {

    var tilesIndexMapping = [[0,-1], [1,-1], [2,-1],[3,-1], [4,-1], [5,-1], [6,-1], [7,-1],[8,-1], [9,-1], [10,-1],[11,-1], [12,-1], [13,-1], [14,-1], [15,-1]]; 


      for (var i = 0; i < 8; i++) {
        //console.log('i is:' + i);
        //create a random value between 0 and 16 
        //corersponding to the tile positions
        var count = 0; 
        while(count < 2) {
          var val = Math.floor(Math.random() * 16);
          console.log('val: ' + val);
          if(tilesIndexMapping[val][1] == -1) {
            tilesIndexMapping[val][1] = i;
            // console.log('val: ' + val);
            console.log('i: ' + i);
            console.log('tilesIndexMapping['+ val+'][1] ' + tilesIndexMapping[val][1]);
            count = count + 1;
          }
          //console.log('val: ' + val);
          //console.log('count: ' + count);
        }
      } 
      return tilesIndexMapping;
  }
  var tilesIndexMapping = createRandomizedTiles();
  tilesIndexMapping.forEach(function (item) {
    console.log(item[1]);
  });

prints out -1 for each i which is wrong.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.