WebKit JS bindings: step by step how to - javascript

I have to admit I'm new to WebKit so asking the right question is not that easy.
What I have is the WebKit from WebKit.org. It updates, builds, I can debug - I got it working on Windows.
What I'm interested in is how to generate the stub files for some IDL files that I have. I understand the high level picture:
Write the interfaces using the IDL language
Generate stub files (.h & .cpp files).
Add your code in the previously generated stub files.
I've specified my IDL files in "WebCore.gypi". I've specified then the path to my IDL files in "WebCore.gyp". Apparently this is not enough as building the WebKit doesn't generate the stub files for my IDL files.
I've suspected at one point that maybe my IDL files contain undefined attributes but everything seems fine.
Any tips? Also, do you know of any explicit "How to"?
Thanks!
Edit 130206:
I dug some more and apparently WebKit interacts with several build systems; for example GYP is for Chromium. I honestly didn't expect that complication so I didn't mention I needed to generate binding for Safari which has a different build system and as such its own unique "how to".
So, the question would now be, how does the Safari build system work? Where do I need to place my IDL files? Thanks!

Well, I can tell you what helped me. Unfortunately I still couldn't find any documentation so a lot of trial and error was involved.
If you want to generate JS bindings for Safari you have to:
Modify 'DerivedSources.make'.
Make sure your IDL files are correct.
'DerivedSources.make' can be found in '\WebKit\Source\WebCore\'. Inside this make file you have to specify the following:
The path to your folder (containing the IDL files) in 'VPATH'.
Each and all of your IDL files in 'BINDINGS_IDLS'.
Again the path to your folder in 'IDL_INCLUDES'.
Build WebKit. If after this step you still can't see your JSXXX.h and JSXXX.cpp files (genererated for each XXX.IDL file) than you have to check your IDL files.
In my case nothing was generated after the build step and I got an error like this:
6>Next token should be implements, but MyModule at module MyModule {
6> IDLParser.pm:750 at /WebKit/Source/WebCore/bindings/scripts//IDLParser.pm line 129.
6> in /WebKit/Source/WebCore/MyFolder/XXX.idl at /WebKit/Source/WebCore/bindings/scripts//IDLParser.pm line 173.
6>/WebKit/Source/WebCore/DerivedSources.make:1024: recipe for target `XXX.h' failed
6>make: * [XXX.h] Error 255
The problem was that each of the IDL interfaces where enclosed in a module (namespace) called MyModule as you can see above. I've removed all this modules (keeping the interfaces of course) and at the next build everything was generated just fine. Using your own module name seems to not be as straight-forward as enclosing the IDL interfaces with it; most probably you'd be forced to write custom bindings to accomplish this (which is not recommended by the WebKit team).
So that was it for me, hope it's also helpful to you.

Related

Check to see if dynamic import is a module in JavaScript/TypeScript

I am working on a ScriptManager class for a project that was created many years ago. The original code read scripts from a database, and these scripts are different depending on the customer and installation (the application is a desktop app that uses Chrome Embedded Framework to display web pages). The code would read custom JavaScript code and eval() it, which of course is highly undesirable.
I am replacing this code with a ScriptManager class that can support dynamically inserted code, and the ScriptManager is capable of loading code as a module using JavaScript's dynamic import() command, or loading code as pure script by creating a script tag dynamically in the document.
My problem is that there are many different possible custom code blocks in the database, and not all are modules; some will be pure script until those can be converted to modules at a later time. My code can handle this as described above, but I need a way to detect if the script code from the database is a module, so I can either use the import() command or insert a script tag if it is not.
I am solving this temporarily by making sure any module script code has "export const isModule = true", and checking this after calling import(). This works, but any code that is pure script still results in a module variable, but with no exports in it. If possible I don't want the other developers to have to remember to add isModule = true to any modules they develop in the future.
Is there a way to check that code is a module without having to do complex analysis of the code to check if there are exports in it? Since import() still returns an object and throws no errors if there are no exports, I don't know how to detect this.
UPDATE: Here are some examples of how this is intended to work:
// Not real code, pretend that function gets the string of the script.
let code = getSomeCodeFromTheDatabase();
// Save the code for later loading.
let filename = 'some-filename.js';
saveCodeToFile(code, filename);
// Attempt to dynamically import the script as a module.
let module = await import(filename);
// If it is NOT a module, load it instead as a script tag.
// This is where I need to be able to detect if the code is
// a module or pure script.
if (!module.isModule) {
let scriptTag = document.createElement('script');
scriptTag.src = filename;
document.head.appendChild(script);
}
So if you look here How can I tell if a particular module is a CommonJS module or an ES6 module? you will see I answered a similar question.
So the thing is Sarah, modules are defined by the way that they resolve. Module-types resolving differently is what, not only makes them incompatible with one another, but it is also why we name them differently. Originally Transpillers like Babel & TypeScript were invented because of differences in ECMA-262 Specifications, and the desire to support people who didn't have the updated specifications, as well as supporting the newer features for those who did.
Today transpilers are still being used, conceptually, much the same way. They still help us maintain a single code base while supporting older specifications, and features in newer specifications, at the same time, but the also have the added benefit of being able to generate multiple different builds from a single code base. They use this to support different module types. In node.js, the primary module-type is CJS, but the future lies in ESM modules, so package maintainers have opted to dual build the projects. The use the TypeScript Compiler (aka Transpiler) to emit a CJS build, and an ESM build.
Now this is where things get complicated, because you cannot tell just by looking at a module if it CJS or ESM in this situation, **you absolutely have to inspect its code, and check if it has more than one tsconfig.json file (because it would need at-least 2 to maintain a bi-modular build (which are becoming increasingly common with the turn of each day)
My Suggestion to You:
Use well documented packages. Good packages should be documented well, and those packages should state in their README.md document, what type of package/module they are, and if the package supports more than one module type. If in doubt you can either come and ask here, or better yet, you can ask the maintainer by creating an issue, asking them to add that information to their README.md document.
You can check that there are no export after import. In chrome import() added empty default for non module.
function isNotModule(module) {
return (!Object.keys(module).length) || (!!module.default && typeof module.default === 'object' && !Object.keys(module.default).length)
}
import('./test.js')
.then((module) => {
console.log('./test.js',isNotModule(module))
})
May be it's better to check source code via regex to check if it contains export
something like this
const reg = new RegExp('([^\w]|^)export((\s+)\w|(\s*{))')
reg.test(source)

Intesllisense methods for expect incorrect

When using intellisense in VS-Code, it gives autocomplete suggestions for an older version of expect than what I'm using,. The API has changed since it was donated to the Jest project, but for some reason, it still shows the old methods, but none of the replacement methods, like toHaveProperty.
Took a lot of effort to find out why my tests weren't working, but haven't been able to find an answer as to what could be the cause.
VS Code sources its type definitions for JavaScript from the #types namespace on NPM, which contains definition files that are automatically pulled from the DefinitelyTyped GitHub repository.
In your case, the type definitions will be coming from the #types/expect package, which specifies in the README that it exposes the files from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/expect.
If you look at the timestamps on said files, you'll notice they haven't been updated in 5 months! That is most likely the source of your issue.
You (or someone else) will need to submit an updated type definition to make automatic type acquisition function properly for that library. Alternatively, you can override the type definitions locally or disable the feature altogether.

Getting this error while trying BDD cucumber Selenium when designing Page object model

Exception in thread "main" cucumber.runtime.CucumberException: java.lang.AbstractMethodError: cucumber.runtime.java.picocontainer.PicoFactory.addClass(Ljava/lang/Class;)V
at cucumber.runtime.java.JavaBackend.addStepDefinition(JavaBackend.java:154)
at cucumber.runtime.java.MethodScanner.scan(MethodScanner.java:68)
at cucumber.runtime.java.MethodScanner.scan(MethodScanner.java:41)
at cucumber.runtime.java.JavaBackend.loadGlue(JavaBackend.java:86)
at cucumber.runtime.Runtime.(Runtime.java:91)
at cucumber.runtime.Runtime.(Runtime.java:69)
at cucumber.runtime.Runtime.(Runtime.java:65)
at cucumber.api.cli.Main.run(Main.java:35)
at cucumber.api.cli.Main.main(Main.java:18)
Caused by: java.lang.AbstractMethodError: cucumber.runtime.java.picocontainer.PicoFactory.addClass(Ljava/lang/Class;)V
at cucumber.runtime.java.JavaBackend.addStepDefinition(JavaBackend.java:149)
... 8 more
The problem is that cucumber cannot find your glue libraries. The commandline runner is in the stack trace which suggests that you are not following the syntax rules for CLI. Here is an example:
mvn clean test -Dcucumber.options="--tags #search --monochrome --plugin pretty:STDOUT --plugin html:target/cucumber-html-report --plugin json:target/cucumber.json --glue steps --glue runsupport classpath:features"
Note the double dash characters before keywords. Also notice that since there are two glue paths that there are two --glue clauses. Also note that only the package name of the two -glue paths were specified.
Further note that STDOUT needed to be specified on --plugin pretty:STDOUT.
Finally note that the features keyword was dropped completely. The path specified at the end (without a keyword) tells cucumber-jvm where to find the feature files.
Be warned, if you get any of this wrong then cucumber-jvm gives you cryptic error messages with which you have first hand knowledge. The usage is explained here.
BTW, claspath: refers to, in this case, the Maven default classpath which for features is
src/test/resources/
If you want help in the future post the minimum code necessary to reproduce the problem. Remember that your brain is not a network connected device. :-)

TypeScript use typescript-require shared files

I use TypeScript to code my javascript file with Object Oriented Programing.
I want to use the node module https://npmjs.org/package/typescript-require to require my .ts files from other files.
I want to share my files in both server and client side. (Browser) And that's very important. Note that the folder /shared/ doesn't mean shared between client and server but between Game server and Web server. I use pomelo.js as framework, that's why.
For the moment I'm not using (successfully) the typescript-require library.
I do like that:
shared/lib/message.js
var Message = require('./../classes/Message');
module.exports = {
getNewInstance: function(message, data, status){
console.log(requireTs);// Global typescript-require instance
console.log(Message);
return new Message(message, data, status);
}
};
This file need the Message.js to create new instances.
shared/classes/Message.ts
class Message{
// Big stuff
}
try{
module.exports = Message;
}catch(e){}
At the end of the fil I add this try/catch to add the class to the module.exports if it exists. (It works, but it's not really a good way to do it, I would like to do better)
If I load the file from the browser, the module.export won't exists.
So, what I did above is working. Now if I try to use the typescript-require module, I'll change some things:
shared/lib/message.js
var Message = requireTs('./../classes/Message.ts');
I use requireTs instead of require, it's a global var. I precise I'm using .ts file.
shared/classes/Message.ts
export class Message{
// Big stuff
}
// remove the compatibility script at the end
Now, if I try like this and if I take a look to the console server, I get requireTs is object and Message is undefined in shared/lib/message.js.
I get the same if I don't use the export keyword in Message.ts. Even if I use my little script at the end I get always an error.
But there is more, I have another class name ValidatorMessage.ts which extends Message.ts, it's not working if I use the export keyword...
Did I did something wrong? I tried several other things but nothing is working, looks like the typescript-require is not able to require .ts files.
Thank you for your help.
Looking at the typescript-require library, I see it hasn't been updated for 9 months. As it includes the lib.d.ts typing central to TypeScript (and the node.d.ts typing), and as these have progressed greatly in the past 9 months (along with needed changes due to language updates), it's probably not compatible with the latest TypeScript releases (just my assumption, I may be wrong).
Sharing modules between Node and the browser is not easy with TypeScript, as they both use very different module systems (CommonJS in Node, and typically something like RequireJS in the browser). TypeScript emits code for one or the other, depending on the --module switch given. (Note: There is a Universal Module Definition (UMD) pattern some folks use, but TypeScript doesn't support this directly).
What goals exactly are you trying to achieve, and I may be able to offer some guidance.
I am doing the same and keep having issues whichever way I try to do things... The main problems for me are:
I write my typescript as namespaces and components, so there is no export module with multiple file compilation you have to do a hack to add some _exporter.ts at the end to add the export for your library-output.js to be importable as a module, this would require something like:
module.exports.MyRootNamespace = MyRootNamespace
If you do the above it works, however then you get the issue of when you need to reference classes from other modules (such as MyRootNamespace1.SomeClass being referenced by MyRootNamespace2.SomeOtherClass) you can reference it but then it will compile it into your library-output2.js file so you end up having duplicates of classes if you are trying to re-use typescript across multiple compiled targets (like how you would have 1 solution in VS and multiple projects which have their own dll outputs)
Assuming you are not happy with hacking the exports and/or duplicating your references then you can just import them into the global scope, which is a hack but works... however then when you decide you want to test your code (using whatever nodejs testing framework) you will need to mock out certain things, and as the dependencies for your components may not be included via a require() call (and your module may depend upon node_modules which are not really usable with global scope hacking) and this then makes it difficult to satisfy dependencies and mock certain ones, its like an all or nothing sort of approach.
Finally you can try to mitigate all these problems by using a typescript framework such as appex which allows you to run your typescript directly rather than the compile into js first, and while it seems very good up front it is VERY hard to debug compilation errors, this is currently my preferred way but I have an issue where my typescript compiles fine via tsc, but just blows up with a max stack size exception on appex, and I am at the mercy of the project maintainer to fix this (I was not able to find the underlying issue). There are also not many of these sort of projects out there however they make the issue of compiling at module level/file level etc a moot point.
Ultimately I have had nothing but problems trying to wrestle with Typescript to get it to work in a way which is maintainable and testable. I also am trying to re-use some of the typescript components on the clientside however if you go down the npm hack route to get your modules included you then have to make sure your client side uses a require compatible resource/package loader. As much as I would love to just use typescript on my client and my server projects, it just does not seem to want to work in a nice way.
Solution here:
Inheritance TypeScript with exported class and modules
Finally I don't use require-typescript but typescript.api instead, it works well. (You have to load lib.d.ts if you use it, else you'll get some errors on the console.
I don't have a solution to have the script on the browser yet. (Because of export keyword I have some errors client side) I think add a exports global var to avoid errors like this.
Thank you for your help Bill.

Add Subversion revision to included Javascript and CSS files

I'm looking adding Subversion's revision number to the name of each .js file we include, so whenever the .js file is updated, the browsers will automatically fetch the new version.
I believe Stackoverflow does this, but I wonder how. Is this part of the release procedure? Any hints on how to achieve this using Subversion tools?
There is no standard way to have Subversion add the revision to the file name. Use a build tool (for example, ant) and a custom target for this.
If you set the SVN Keyword "Revision" on the file which declares the tag, then the literal text $Revision$ becomes a SVN keyword. Each time you update the working copy, $Revision$ will update to read $Revision 1234 $ where 1234 is the current revision number.
Just be forewarned, we have run into problems with IE6 using this approach. We had put for all our tags (and applied the SVN Revision keyword to them) so that every time we push a new copy of code out to our production boxes, we know all clients will get the current revision. But IE6 sometimes creates weird errors when this happens; as though you were missing some of those script tags. In the end we took them out because it caused us more problems with IE6 than it ever solved us.

Categories