I want that when converting haxe to JavaScript, asynchronous is added to its methods.
I have Haxe code:
#:expose
class Main implements IAsync {
static function main() {
trace("test");
}
static function testAwait() {
return 1;
}
}
And this code is converted to such a code:
. . .
Main.testAwait = function() {
return Main.test();
};
. . .
I wanted to be able replace function to async function in this code.
For example:
Main.testAwait = async function() {
return Main.test();
};
But I can only change the name of the method for example code macros:
package haxe_test;
import haxe.macro.Expr;
import haxe.macro.Context;
using haxe.macro.Tools;
using haxe_test.AsyncBuilder;
class BuildHub {
macro static public function build():Array<Field> {
var fields = Context.getBuildFields();
var testFunc:Function = {
expr: macro return $v{1},
ret: null,
params: [],
args: []
};
fields.push({
name: "testAwait",
access: [Access.AStatic],
kind: FieldType.FFun(testFunc),
pos: Context.currentPos(),
});
return fields;
}
How replace function to async function?
UPD: I simplified code. Maybe is anythings options compilers or JSGenApi can help me)?
Not sure if you considered something more simple but in Haxe 4 you can do something like this:
class Test {
static function main() {
var value = await( async(testAsync) );
trace(value);
}
static function testAsync() return 1;
static inline function await<T>(fn:Void->Void):T {
return js.Syntax.code("await {0}()", fn);
}
static inline function async<T>(fn:Void->Void):T {
return js.Syntax.code("async () => {0}()", fn);
}
}
or do both at same time:
class Test {
static function main() {
var value = asyncAwait( testAsync );
trace(value);
}
static function testAsync() return 1;
static inline function asyncAwait<T>(fn:Void->Void):T {
return js.Syntax.code("(async () => { await {0}() })()", fn);
}
}
I think your general options would be:
Collect information about async types/fields in build macros, then use that in haxe.macro.Context.onAfterGenerate to modify the output file. Since Haxe code is consistently indented, you can get away with a couple regular expressions (I once made a macro that'd split the output file into multiple by-package files this way).
Make a slightly modified copy of haxe.macro.ExampleJSGenerator to prepend async before method declarations of interest. Since you do not need any changes to expression printing, this is also pretty easy.
Related
I'm new to typescript to bear with me here if this is not how things are supposed to work.
I have a couple of goals in converting this js to ts.
Item = {}
Item.buy = function (id) {}
Item.sell = function (id) {}
I'm trying to get intellisense to autocomplete on Item. either buy or sell. I would also want to use dot notation to create these methods in arbitrary files without putting everything in the initial bracket. So I have something like this:
interface Item {}
const Item: Item = {};
interface Item {
buy?: Function
}
Item.buy = function () {
Item.render()
return "bought"
}
interface Item {
sell?: Function
}
Item.sell = function () {
Item.render()
return "sold"
}
interface Item {
render?: Function
}
Item.render = function () {
return 1
}
The problem here now is that render is an optional property and hence I get this error:
Cannot invoke an object which is possibly 'undefined'.
How can I make ts not check for this error? Since Item is not a class there's only ever going to be 1 item and it'll definitely have the render method, there is not ever going to be an instance where that error checking is useful. Or to put it another way, it's not actually optional, I only set it to be optional to work around const Item: Item = {}; erroring if I don't have it be optional.
Is there a way to let ts know that or use a different pattern in the first place?
SOLUTION 1:
Since you have not defined any method inside Item
interface Item {}
So you can check whether render method exist or not on Item as:
Item.buy = function () {
if(Item.render) Item.render(); // CHANGE
return "bought";
}
SOLUTION 2:
Best solution would be to add type of render on interface Item as:
interface Item {
render: () => void;
}
and then you can use it as:
Item.buy = function () {
Item.render();
return "bought";
}
My inclination here would be to use namespaces instead of an interface to hold these functions. It could look like this:
namespace Item {
export const buy = function () {
Item.render()
return "bought"
}
}
namespace Item {
export const sell = function () {
Item.render()
return "sold"
}
}
namespace Item {
export const render = function () {
return 1
}
}
Then you'd be able to access them the same way, as methods on the singleton Item value:
// elsewhere
console.log(Item.sell()); // "sold"
Note that namespace is a TypeScript specific feature, and nowadays new code is generally encouraged to use modules instead where possible. I don't really know if there's a good way to get this sort of behavior with modules, because the part we're using, merging different things into a common JS value, is not really how modules works. Maybe declaration merging and importing would give this to you, but I don't know.
Anyway, as long as you're okay with a TS-specific feature, then namespace would be an idiomatic way to represent this sort of gradual building of a singleton.
Playground link to code
I have an old IIFE that is injected into legacy pages via <script src.
However, I want to use all these old libraries in a react app. I just need to use the global function exposed.
I figure loading dependencies that will work both via script or via react's import or nodejs require
Here is an example of an example IIFE
example.js :
var $ = $;
var geocomplete = $.fn.geocomplete;
var OtherExternalLib = OtherExternalLib;
var Example = (function() {
return {
init: function () {
// stuff
}
}
)();
Where the legacy code is calling Example.init(), and likewise the react code will call the same function.
Where $ (jQuery), $.fn.geocomplete, and OtherExternalLib are all dependencies that must be loaded, either they should be loaded on-demand or just throw a big loud error message.
I suspect if the solution loads dynamically example.js would look something like
var $ = load("\libs\jquery.js");
var geocomplete = load("\libs\$.fn.geocomplete.js");
var OtherExternalLib = load("\libs\OtherExternalLib.js");
var Example = (function() {
return {
init: function () {
// stuff
}
}
)();
And the legacy application can still use <script src=example.js and React can use
import {Example} from example
Understandably this is somewhat a round-about way to of using legacy code in new applications, so I am open to other ideas on how best to expose an IIFE (with or without dependencies) and using it in React
I am using react+typescript in my project with some limitations which is why I had to dynamically import my package (my project runs in a shell project with AMD module, not having my own startup, and change the way project files get bundled).
Since I could only use the dependent modules on the fly during the run time, I had to assume them were valid while building and bundling . Most of them were IIFE.
So I used the lazy dynamic import .
something like this
import("somePolyfill");
This would be translated by TSC
new Promise(function (resolve_3, reject_3) { require(["arrayPolyfill"], resolve_3, reject_3); });
This would call the IIFE and execute the polyfills or initializing any window or global variable, so the rest of the code is aware of that.
If it returns a module or throughs error can be handled like normal promise then and catch.
So I created a wrapper
export class DepWrap {
public static Module: any = {};
public constructor() {
this.getPI();
this.getSomeModule();
}
public async getPI() {
DepWrap.Module["PI"] = 3.14;
}
public async getSomeModule() {
await import('somepath/somemodule').then(($package) => {
DepWrap.Module["somemodule"] = $package;
}).catch(() => {
window.console.log("Some Module error");
});
}
}
this got compiled to
define(["require", "exports", "tslib"], function (require, exports, tslib_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var DepWrap = /** #class */ (function () {
function DepWrap() {
this.getPI();
this.getSomeModule();
}
DepWrap.prototype.getPI = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
DepWrap.Module["PI"] = 3.14;
return [2 /*return*/];
});
});
};
DepWrap.prototype.getSomeModule = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, new Promise(function (resolve_1, reject_1) { require(['somepath/somemodule'], resolve_1, reject_1); }).then(function ($package) {
DepWrap.Module["somemodule"] = $package;
}).catch(function () {
window.console.log("Some Module error");
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
DepWrap.Module = {};
return DepWrap;
}());
exports.DepWrap = DepWrap;
});
with this I could use all the dependency modules from my wrapper and every time i need to import a new one I would create another function to add that to my wrap module.
import { DepWrap } from "wrapper/path";
const obj = new DepWrap(); // initialize once in the beginning of project so it would import all the dependencies one by one .
Afterwards in all file, I can import my module from the wrapper
import { DepWrap } from "wrapper/path";
const { PI, somemodule} = DepWrap.Module;
I am not sure if the code will work for your scenario as well, but I guess tweaking it a bit might come in handy for your useCase .
Plus : if you are writing unit test case it will help jest to just ignore the modules and can create a mock for this so that you can test your actual code .
I have 3 classes, all extend the previous one.
Entity -> Body -> Player
Each one has a die() method which do very different things.
Entity.die() will call the db
Body.die() will animate the body
Player.die() will call the UI and play special sound.
I don't want to manually call Entity.die() inside Body.die method, mainly because I have many classes and many common methods and I don't want to forget something.
I wrote this little piece of code which does exactly this, the Error stack is easy to understand and points to the correct lines.
function overLoadMethods (parent, children) {
const methods = {}
for (let [fname, fn] of Object.entries(parent)) {
if (typeof fn === 'function') {
if (children[fname]) {
methods[fname] = function () {
fn()
children[fname]()
}
Object.defineProperty(methods[fname], 'name', { value: fname })
} else {
methods[fname] = fn
}
}
}
return methods
}
function createEntity () {
return {
die: () => {
console.log(new Error().stack)
console.log('entity die')
}
}
}
const bodyMethods = {
die: () => {
console.log(new Error().stack)
console.log('body die')
}
}
function createBody () {
const entity = createEntity()
const overLoadedMethods = overLoadMethods(entity, bodyMethods)
return {
...entity,
...bodyMethods,
...overLoadedMethods
}
}
const playerMethods = {
die: () => {
console.log(new Error().stack)
console.log('player die')
}
}
function createPlayer () {
const body = createBody()
const overLoadedMethods = overLoadMethods(body, playerMethods)
return {
...body,
...playerMethods,
...overLoadedMethods
}
}
const player = createPlayer()
// will call Entity.die() then Body.die() then Player.die()
player.die()
Everything is working fine but I never saw this pattern before and I guess there is a good reason which I'm unaware of.
Could someone point the weakness of this pattern if there is one (pretty sure there is) ?
Common Lisp has something similar. When you define a method in a derived class you can decide whether this method should be executed:
:before (i.e. the base method will be called automatically after specialized one)
:after (i.e. the base method will be called automatically before the specialized one)
:around (i.e. only the specialized method will be called, but inside its body you can call the base method with call-next-method that is a special syntax that allows calling base method with either the parameters specified by the caller or the parameters that you want to pass instead).
For example C++ only has around available for general methods (but without the ability to call the base version with original parameters) and forces instead use of before in constructor and after in destructors.
I understand the desire to not repeat code and create code that makes it hard to make mistakes and forget things. But you still have code the you need to remember to wire up. For example, instead of calling Entity.die() you need to call overLoadMethods(). I'm not sure that's an improvement over regular of classes and calling super.die().
You can get the chained method behavior using ES6 classes (you can also get it using prototypes). This has a lot of advantages:
• The pattern is baked into the language.
• It's very clear to see parent/child relationship
• There's a lot of commentary, theory, and examples of different patterns
class Entity {
die() {
// Entity-specific behavior
console.log('entity die')
}
}
class Body extends Entity {
die() {
super.die()
// Body-specific behavior
console.log('body die')
}
}
class Player extends Body {
die() {
super.die()
// Player-specific behavior
console.log('player die')
}
}
const player = new Player
// will call Entity.die() then Body.die() then Player.die()
player.die()
I am quite new to writing javascript code using AMD. I am stuck at figuring out how to write multiple functions in a file:
define(function(){
return {
and: function(a,b){
return (a&&b);
}
};
}
);
I tried writing another function plus in the following way:
define(function(){
return {
plus: function(a,b){
return (a+b);
}
};
}
);
But when I use grunt for testing, it is not able to detect the function plus
You should place each module in it's own file. At least requireJS (are you using that?) determines the module name by it's file name (without the .js).
So a file sitting in /modules/A.js will have the module name "modules/A".
If you really want to define multiple modules in one file, you can do it in a more explicit way like this:
define("A", [], function () { return ...whatever... });
define("B", [], function () { return ...whatever... });
Edit:
for defining one module with two functions you can use different patterns. For a singleton (i.e. no "Class") I usually do something like this:
define(function () {
var myModule = {
fn1: function () { .... },
fn2: function () { .... }
};
return myModule;
});
I want to set up a manager with a handler object that provides a specific function for each request. Why is only syntax a) working in other sample code I saw syntax b)
a)
my.manager.requesthandler.create();
.
b)
my.manager.requesthandler [create]();
.
// my manager-modul
(function(){
my.manager = (function(){
var requesthandler = {
create: function () {
//do something
}
};
return {
requesthandler : requesthandler
};
})();
})();
my.manager.requesthandler.create
is equivalent to
my.manager.requesthandler["create"]
(notice the quotation marks)
what you wrote as b
my.manager.requesthandler[create]
means looking up a variable named create and getting
my.manager.requesthandler["whatever string create's value is"]