CoffeeScript can't use spread operator with class fields - syntax

I can't understand why this syntax of spread method is wrong for CoffeeScript in WebStorm
class Test
fruit: {apple: "apple"}
init: ->
console.log 1, #fruit
spread: ->
console.log 2, {#fruit...}
spreadWithVar: ->
fruit = #fruit
console.log 3, {fruit...}
test = new Test()
test.init()
test.spread()
test.spreadWithVar()
After compiling I get this JS code:
(function() {
var Test, test;
Test = (function() {
class Test {
init() {
return console.log(1, this.fruit);
}
spread() {
return console.log(2, {...this.fruit});
}
spreadWithVar() {
var fruit;
fruit = this.fruit;
return console.log(3, {...fruit});
}
};
Test.prototype.fruit = {
apple: "apple"
};
return Test;
}).call(this);
test = new Test();
test.init();
test.spread();
test.spreadWithVar();
}).call(this);
1 { apple: 'apple' }
2 { apple: 'apple' }
3 { apple: 'apple' }
To run code and see result in online compiler: jdoodle.com/ia/qQh
All three methods work fine when it compiled and give to me an expected JavaScript code. But as in online editor in WebStorm I get errors about of syntax #name...:
and
And I can not understand why? If it gives to me a correct JavaScript code, why does it think that this is wrong for CoffeeScript?

As you fixed your errors in gulp by updating gulp-coffee to the latest version, I think the webstorm problem is likely to have a similar solution.
Looking at the webstorm coffeescript documentation, they mention that it depends on a globally installed coffeescript package.
First check if your global coffeescript is outdated:
npm outdated -g --depth=0
Then you can go ahead and update it:
npm update -g coffeescript

Related

Parse iOS Universal Links with Nativescript Angular?

Following the apple documentation and Branch's documentation here, I have set up a working universal link in my Nativescript Angular (iOS) app. But, how do I parse the link when the app opens?
For example, when someone opens the app from the link, I want to have my app read the link so it can go to the correct page of the app.
There is some helpful code in this answer, but I keep getting errors with it. This could be bc the code is written in vanilla JS and I am not translating it into Angular correctly. The use of "_extends" and "routeUrL" both cause errors for me.
And the Nativescript url-handler plugin does not seem to work without further code.
So, after setting up the universal link, and installing the nativescript url-handler plugin, I have entered the following in app.module.ts:
const Application = require("tns-core-modules/application");
import { handleOpenURL, AppURL } from 'nativescript-urlhandler';
declare var NSUserActivityTypeBrowsingWeb
if (Application.ios) {
const MyDelegate = (function (_super) {
_extends(MyDelegate, _super);
function MyDelegate() {
_super.apply(this, arguments);
}
MyDelegate.prototype.applicationContinueUserActivityRestorationHandler = function (application, userActivity) {
if (userActivity.activityType === NSUserActivityTypeBrowsingWeb) {
this.routeUrl(userActivity.webpageURL);
}
return true;
};
MyDelegate.ObjCProtocols = [UIApplicationDelegate];
return MyDelegate;
})(UIResponder);
Application.ios.delegate = MyDelegate;
}
...
export class AppModule {
ngOnInit(){
handleOpenURL((appURL: AppURL) => {
console.log('Got the following appURL = ' + appURL);
});
}
}
The trouble seems to be mostly with "_extends" and "_super.apply". For example, I get this error:
'NativeScript encountered a fatal error: TypeError: undefined is not an object (evaluating '_extends')
EDIT: Note that the nativescript-urlhandler plugin is no longer being updated. Does anyone know how to parse universal links with Nativescript?
I have figured out a method to get this working:
The general idea is to use the iOS App Delegate method: applicationContinueUserActivityRestorationHandler.
The syntax in the Nativescript documentation on app delegates did not work for me. You can view that documentation here.
This appears to work:
--once you have a universal link set up, following documentation like here, and now you want your app to read ("handle") the details of the link that was tapped to open the app:
EDIT: This code sample puts everything in one spot in app.module.ts. However, most of the time its better to move things out of app.module and into separate services. There is sample code for doing that in the discussion here. So the below has working code, but keep in mind it is better to put this code in a separate service.
app.module.ts
declare var UIResponder, UIApplicationDelegate
if (app.ios) {
app.ios.delegate = UIResponder.extend({
applicationContinueUserActivityRestorationHandler: function(application, userActivity) {
if (userActivity.activityType === NSUserActivityTypeBrowsingWeb) {
let tappedUniversalLink = userActivity.webpageURL
console.log('the universal link url was = ' + tappedUniversalLink)
}
return true;
}
},
{
name: "CustomAppDelegate",
protocols: [UIApplicationDelegate]
});
}
NOTE: to get the NSUserActivity/Application Delegate stuff to work with typescript, I also needed to download the tns-platforms-declarations plugin, and configure the app. So:
$ npm i tns-platforms-declarations
and
references.d.ts
/// <reference path="./node_modules/tns-platform-declarations/ios.d.ts" />
The above code works for me to be able to read the details of the tapped universal link when the link opens the app.
From there, you can determine what you want to do with that information. For example, if you want to navigate to a specific page of your app depending on the details of the universal link, then I have found this to work:
app.module.ts
import { ios, resumeEvent, on as applicationOn, run as applicationRun, ApplicationEventData } from "tns-core-modules/application";
import { Router } from "#angular/router";
let univeralLinkUrl = ''
let hasLinkBeenTapped = false
if (app.ios) {
//code from above, to get value of the universal link
applicationContinueUserActivityRestorationHandler: function(application, userActivity) {
if (userActivity.activityType === NSUserActivityTypeBrowsingWeb) {
hasLinkBeenTapped = true
universalLinkUrl = userActivity.webpageURL
}
return true;
},
{
name: "CustomAppDelegate",
protocols: [UIApplicationDelegate]
});
}
#ngModule({...})
export class AppModule {
constructor(private router: Router) {
applicationOn(resumeEvent, (args) => {
if (hasLinkBeenTapped === true){
hasLinkBeenTapped = false //set back to false bc if you don't app will save setting of true, and always assume from here out that the universal link has been tapped whenever the app opens
let pageToOpen = //parse universalLinkUrl to get the details of the page you want to go to
this.router.navigate(["pageToOpen"])
} else {
universalLinkUrl = '' //set back to blank
console.log('app is resuming, but universal Link has not been tapped')
}
})
}
}
You can use the nativescript-plugin-universal-links plugin to do just that.
It has support for dealing with an existing app delegate so if you do have another plugin that implements an app delegate, both of them will work.
Here's the usage example from the docs:
import { Component, OnInit } from "#angular/core";
import { registerUniversalLinkCallback } from "nativescript-plugin-universal-links";
#Component({
selector: "my-app",
template: "<page-router-outlet></page-router-outlet>"
})
export class AppComponent {
constructor() {}
ngOnInit() {
registerUniversalLinkCallback(ul => {
// use the router to navigate to the screen
});
}
}
And the callback will receive a ul (universal link) param that looks like this
{
"href": "https://www.example.com/blog?title=welcome",
"origin": "https://www.example.com",
"pathname": "/blog",
"query": {
"title": "welcome"
}
}
Disclaimer: I'm the author of the plugin.

Specify the webpack "mainFields" on a case by case basis

Webpack has a resolve.mainFields configuration: https://webpack.js.org/configuration/resolve/#resolvemainfields
This allows control over what package.json field should be used as an entrypoint.
I have an app that pulls in dozens of different 3rd party packages. The use case is that I want to specify what field to use depending on the name of the package. Example:
For package foo use the main field in node_modules/foo/package.json
For package bar use the module field in node_modules/bar/package.json
Certain packages I'm relying on are not bundled in a correct manner, the code that the module field is pointing to does not follow these rules: https://github.com/dherman/defense-of-dot-js/blob/master/proposal.md This causes the app to break if I wholesale change the webpack configuration to:
resolve: {
mainFields: ['module']
}
The mainFields has to be set to main to currently get the app to work. This causes it to always pull in the CommonJS version of every dependency and miss out on treeshaking. Hoping to do something like this:
resolve: {
foo: {
mainFields: ['main']
},
bar: {
mainFields: ['module'],
}
Package foo gets bundled into my app via its main field and package bar gets bundled in via its module field. I realize the benefits of treeshaking with the bar package, and I don't break the app with foo package (has a module field that is not proper module syntax).
One way to achieve this would be instead of using resolve.mainFields you can make use of resolve.plugins option and write your own custom resolver see https://stackoverflow.com/a/29859165/6455628 because by using your custom resolver you can programmatically resolve different path for different modules
I am copy pasting the Ricardo Stuven's Answer here
Yes, it's possible. To avoid ambiguity and for easier implementation,
we'll use a prefix hash symbol as marker of your convention:
require("#./components/SettingsPanel");
Then add this to your configuration file (of course, you can refactor
it later):
var webpack = require('webpack');
var path = require('path');
var MyConventionResolver = {
apply: function(resolver) {
resolver.plugin('module', function(request, callback) {
if (request.request[0] === '#') {
var req = request.request.substr(1);
var obj = {
path: request.path,
request: req + '/' + path.basename(req) + '.js',
query: request.query,
directory: request.directory
};
this.doResolve(['file'], obj, callback);
}
else {
callback();
}
});
}
};
module.exports = {
resolve: {
plugins: [
MyConventionResolver
]
}
// ...
};
resolve.mainFields not work in my case, but resolve.aliasFields works.
More details in https://stackoverflow.com/a/71555568/7534433

How do I use Jasmine to test a Phaser 3 project?

I am currently developing a minigame in the phaser.js framework, and since the scope of the project is quite large, I really want to work with unit tests.
However when trying to setup unit tests in Jasmine for Phaser, I run into errors regarding dependencies.
I am not experienced with Jasmine or any other testing framework, so it could be I am overlooking something obvious to a experienced developer.
My .spec file looks like this:
describe("motorMain", function() {
var Phaser = require('../phaser');
var MotorMain = require("../motorMain");
var motorMain;
var phaser;
beforeEach(function() {
phaser = new Phaser();
motorMain = new motorMain();
});
it("should increase the score if a object is clicked", function(){
var scoreBeforeClicking = motorMain.score;
var gameobject;
motorMain.clickhandler("",gameobject);
expect(scoreBeforeClicking+1).toEqual(score);
})
});
But since Phaser is reliant on running in a browser, when I run this it complains about not being able to access elements such as window and document in Phaser.
I get errors such as:
ReferenceError: document is not defined
Does anyone have experience with testing Phaser games? I can't seem to find any information on it online. Is it even possible to test phaser games?
As for other testing frameworks, I also looked into nightwatch, but it's Phaser support is outdated, and it is mainly e2e instead of unit-testing, so it isn't what I am looking for. I also saw online that there was a shimming version of Phaser 2.4.7 developed by someone, but this is outdated now that so much has changed in Phaser 3.
Ok, I've got something working!
This is the bare minimum, but Phaser can be instantiated without errors.
package.json
{
"scripts": {
"test": "jasmine --config=jasmine.json"
},
"devDependencies": {
"canvas": "^2.8.0",
"jasmine": "^3.7.0",
"jsdom": "^16.6.0",
"jsdom-global": "^3.0.2"
},
"dependencies": {
"phaser": "^3.55.2"
}
}
jasmine.json
{
"spec_dir": "spec",
"spec_files": [
"**/*[sS]pec.js"
]
}
spec/Phaser.Spec.js
require('canvas');
require('jsdom-global')();
const Phaser = require("phaser");
describe("A suite", function () {
it("Instantiate a Phaser.Game", function () {
let game = new Phaser.Game({ type: Phaser.HEADLESS });
expect(game).not.toBe(null);
})
})
The output in console is:
$ jasmine --config=jasmine.json
Randomized with seed 06585
Started
Phaser v3.55.2-FB (Headless | HTML5 Audio) https://phaser.io
.
1 spec, 0 failures
Finished in 0.016 seconds
Randomized with seed 06585 (jasmine --random=true --seed=06585)
✨ Done in 1.28s.

How to use Fable output to other JS projects

I have a small fs file code
module FableApp
open Fable.Import.Browser
let sum x y=
x+y
let myfunct=
let result=sum 5 10
console.log(result)
I am trying to compile it to JS and use in other projects. I have seen that its possible through Fable Repl but I want to do pragmatically. As I need to compile FsProjects in future.
When I tried to compile this using webpack then I got this code
(window.webpackJsonp= window.webpackJsonp|| []).push([
[0],
[function(n, o, t) {
"use strict";
function c(n, o) {
return n + o | 0
}
t.r(o), t.d(o, "Sum", function() {
return c
}), t.d(o, "myfunct", function() {
return r
});
var r = function() {
var n = 0 | c(5, 10);
console.log(n)
}()
}]
]);
According to your requirements I think that the fable-splitter npm package would be exactly the thing you are looking for.
As described in the documentation you would add a line to the scripts block of your package.json file in which you tell the script runner to build your project and put the unbundled files to the output location.
"scripts": {
"build": "fable-splitter src/MyProject.fsproj --outDir out"
}
There are more fine grained configuration options I'd suggest you look at the documentation to get acquainted with the API in case you should need it. If you want to use the configuration in your build you would change the script block to include a configuration parameter pointing to the config file.
"scripts": {
"build": "fable-splitter --config splitter.config.js"
}

Testing Yeoman generator with bowerInstall and/or npmInstall

I have a Yeoman generator that uses this.bowerInstall()
When I test it, it tries to install all the bower dependencies that I initialized this way. Is there a way to mock this function ?
The same goes for the this.npmInstall() function.
I eventually went with a different approach. The method from drorb's answer works if you are bootstrapping the test generators manually. If you use the RunContext based setup (as described on the Yeoman (testing page)[http://yeoman.io/authoring/testing.html]), the before block of the test looks something like this.
before(function (done) {
helpers.run(path.join( __dirname, '../app'))
.inDir(path.join( __dirname, './tmp')) // Clear the directory and set it as the CWD
.withOptions({ foo: 'bar' }) // Mock options passed in
.withArguments(['name-x']) // Mock the arguments
.withPrompt({ coffee: false }) // Mock the prompt answers
.on('ready', function (generator) {
// this is called right before `generator.run()`
})
.on('end', done);
})
You can add mock functions to the generator in the 'ready' callback, like so:
.on('ready', function(generator) {
generator.bowerInstall = function(args) {
// Do something when generator runs bower install
};
})
The other way is to include an option in the generator itself. Such as:
installAngular: function() {
if (!this.options['skip-install']) {
this.bowerInstall('angular', {
'save': true
});
}
}
finalInstall: function() {
this.installDependencies({
skipInstall: this.options['skip-install']
});
}
Now since you run the test with the 'skip-install' option, the dependencies are not installed. This has the added advantage of ensuring the command line skip-install argument works as expected. In the alternate case, even if you run the generator with the skip-install argument, the bowerInstall and npmInstall functions from your generator are executed even though, the installDependencies function is not (as it is usually configured as above)
Take a look at the tests for the Bootstrap generator, it contains an example of mocking the bowerInstall() function:
beforeEach(function (done) {
this.bowerInstallCalls = [];
// Mock bower install and track the function calls.
this.app.bowerInstall = function () {
this.bowerInstallCalls.push(arguments);
}.bind(this);
}.bind(this));

Resources