Difference between pages "JavaScript Support" and "File:Intellij-setup-c2021.2-project-structure-libraries-choose-modules.png"

From Kolmafia
(Difference between pages)
Jump to navigation Jump to search
 
(Screenshot from IntelliJ IDEA 2021.2 Community Edition on Windows 10)
 
Line 1: Line 1:
As of revision 20509, KoLmafia supports scripting in JavaScript! You can run JS code from the CLI using <code>js <nowiki><code></nowiki></code>, and you can call scripts through any of the normal methods. Consult and "lifecycle" scripts (e.g. <code>betweenBattleScript</code>) are supported as well as of revision 20519. '''This support is still experimental - you have been warned.'''
+
== Summary ==
 
+
Screenshot from IntelliJ IDEA 2021.2 Community Edition on Windows 10
== Basics ==
 
* All the methods in the ASH runtime library are available, with names of methods converted to camelCase. So, for example, <code>print_html</code> in ASH becomes <code>printHtml</code> in JS.
 
* In scripts called from a file, you can access the runtime library by calling <code>require("kolmafia")</code>, so <code>const { printHtml } = require("kolmafia")</code>. If running from the command line via <code>js</code>, the runtime library functions are all available in the global scope (so you can do <code>js print("Hello world!");</code>).
 
** If you want all runtime functions available, you can use <code>const k = require("kolmafia")</code>, and then call functions using <code>k.printHtml("Hello world!");</code> (as an example)
 
* ASH maps are converted to plain JS objects, and ASH arrays are converted to JS arrays.
 
* You can look at the type reference for the JS version of the ASH runtime library with <code>jsref</code>, which works just like <code>ashref</code>.
 
* Mafia supports <code>require</code> for both ASH and JS scripts. For ASH scripts, it will execute top-level code but only export functions, not variables, in the top scope.
 
* If you want Mafia to run your <code>main</code> function, you '''<u>must</u>''' export it by adding it to module.exports, just as you would for a Node module. For the uninitiated, this just means adding <code>module.exports.main = main</code> to the end of your script. You will want to do the same with any function or value you want to be available to other scripts via require.
 
 
 
=== Data Type Classes ===
 
All [[Data Types#Special Datatypes|enumerated data types]] in ASH are available as classes. For example, {{type|monster}} is available as the <code>Monster</code> class, and {{type|item}} is available as the <code>Item</code> class.
 
 
 
Each enumerated class has the following static methods:
 
 
 
* <code><ClassName>.get()</code> takes a number or string and returns an object of the class.
 
** For example, <code>Monster.get("fiendish can of asparagus")</code> is equivalent to <code>$monster[ fiendish can of asparagus ]</code> in ASH. <code>Item.get(1)</code> is equivalent to <code>$item[ 1 ]</code>.
 
** This also accepts string representations of integers. For example, <code>Item.get(5)</code> and <code>Item.get("5")</code> return the same result.
 
* <code><ClassName>.get()</code> can also take an array of numbers and strings, and return an array of objects.
 
** For example, <code>Item.get(["seal-clubbing club", "pail", 5])</code> is similar to <code>$items[ seal-clubbing club, pail, 5 ]</code> in ASH. However, the JavaScript version returns an array of objects, instead of a boolean map.
 
** Passing an empty array returns an empty array (i.e. <code>Item.get([])</code> is ''not'' the same as <code>$items[]</code>).
 
* <code><ClassName>.all()</code> takes no argument and returns all possible values of the class.
 
** For example, <code>Monster.all()</code> returns an array of all known monsters. This is similar to <code>$monsters[]</code> in ASH.
 
 
 
Enumerated objects support the <code>toString()</code> method, which acts like the {{f|to_string}} ASH function.
 
 
 
Note: As of r20620, KoLmafia no longer provides a custom <code>valueOf()</code> method for enumerated objects. This means that you can no longer retrieve the ID of an item, effect, or familiar using <code>Number()</code>. Instead, use the {{f|to_int|toInt}} library function.
 
 
 
Example:
 
<syntaxhighlight lang="js">
 
let item = Item.get("filthy lucre");
 
let itemId = toInt(item);
 
</syntaxhighlight>
 
 
 
== ASH and JavaScript Interoperability ==
 
 
 
JavaScript scripts can <code>require()</code> ASH scripts and use their functions. When an ASH script is <code>require()</code>-ed by JavaScript code, KoLmafia will execute top-level code, but only export functions in the top-level scope. ASH variables are not exported.
 
 
 
For example, you can use [[Zlib]] if it is installed:
 
 
 
<syntaxhighlight lang="js" line>
 
const { getvar } = require("zlib.ash");
 
let myvar = getvar("SOME_VAR_NAME");
 
</syntaxhighlight>
 
 
 
ASH scripts cannot <code>import</code> JavaScript scripts.
 
 
 
== JavaScript Version and Features ==
 
KoLmafia uses the [[wikipedia:Rhino (JavaScript engine)|Rhino]] engine to execute JavaScript code. Rhino supports an older version of JavaScript called "ES5", plus some features from newer versions. This means that many JavaScript features that work in web browsers might not work in KoLmafia.
 
 
 
Here is an incomplete list of post-ES5 features supported by Rhino ([https://kolmafia.us/threads/javascript-bugs.25638/post-160384 source]):
 
 
 
=== Supported ===
 
* Syntax
 
** <code>let</code> and (partially) <code>const</code>
 
*** Does not support block-level scoping or temporal dead zones, meaning that you cannot use <code>const</code> for loop variables. <code>for (const a in obj) { ... }</code> is a syntax error.
 
** Array/object destructuring (but spread/rest syntax (<code>...</code>) is ''not'' supported)
 
** <code>for...of</code> loop
 
** Arrow functions: <code>() => {}</code>
 
** Octal and binary literals
 
* Features
 
** Symbol
 
** Set, Map, WeakSet, WeakMap
 
** ES2015 methods in Array, Math, Number, Object, String
 
** <code>Array.prototype.includes()</code>
 
** <code>String.prototype.padStart()/padEnd()/trimStart()/trimEnd()</code>
 
** TypedArray: Can be constructed, but most TypedArray-specific methods are unavailable.
 
 
 
=== Unsupported ===
 
* Syntax
 
** Spread/rest syntax (<code>...</code>)
 
** Template string literals: Backtick string literals (<code>``</code>) are not a syntax error, but are treated as plain string literals.
 
** Classes
 
** ECMAScript modules (<code>import</code>/<code>export</code>)
 
** Default function parameters
 
** Computed property names
 
** Async/Await
 
** Trailing commas in function definitions (oddly, trailing commas are supported in function ''calls'')
 
* Features
 
** Promise
 
** Proxy
 
** Reflect
 
 
 
=== Other ===
 
Most JavaScript globals available in browsers and/or server-side environments like Node.js are ''not'' available. This includes <code>alert()</code>, <code>console.log()</code>, and <code>setTimeout()</code>.
 
 
 
== Transpiling ==
 
 
 
Folks with experience doing JavaScript web development are likely well-acquainted with tools such as Babel, Webpack, and TypeScript. These tools allow you to write modern JavaScript code. and can transpile the code down to an older version of JS supported by a particular engine. That approach works well with Rhino.
 
 
 
* Babel: As of r20558, you will still need to apply several patches to Babel in order to get babel-preset-env to work. See [https://github.com/phulin/bean-casual/tree/ts] for an example of a working Babel/Webpack/Typescript configuration; you'll need the configuration files and also the patches, which can be applied with patch-package.
 
 
 
=== TypeScript ===
 
If you use TypeScript without Babel, you can set the <code>[https://www.typescriptlang.org/tsconfig#target target]</code> to <kbd>"ES5"</kbd>.
 
 
 
TypeScript does not provide [[wikipedia:Polyfill (programming)|polyfills]] for missing globals and methods. To use them, you must supply your own.
 
 
 
To avoid accidentally using any missing functions, we recommend using the following configuration for your <code>tsconfig.json</code>:
 
 
 
<syntaxhighlight lang="js">
 
{
 
  "compilerOptions": {
 
    // JavaScript APIs supported by Rhino 1.7.13
 
    // See https://mozilla.github.io/rhino/compat/engines.html for more info
 
    "lib": [
 
      "ES5",
 
      "ES2015.Collection",
 
      "ES2015.Core",
 
      "ES2015.Generator",
 
      "ES2015.Iterable",
 
      "ES2015.Symbol",
 
      "ES2015.Symbol.WellKnown",
 
      "ES2016.Array.Include",
 
      "ES2017.String",
 
      "ES2019.String"
 
    ],
 
    // Rhino uses require() instead of import/export
 
    // Note: If you use Webpack or Rollup, change this to "ES2015"
 
    "module": "CommonJS",
 
    // Rhino supports ES5+
 
    "target": "ES5"
 
  }
 
}
 
</syntaxhighlight>
 
 
 
If you use a bundler such as [https://webpack.js.org/ Webpack] or [https://rollupjs.org/ Rollup], you should change the <code>module</code> to <kbd>"ES2015"</kbd>, and let the bundlers convert your code to CommonJS.
 

Latest revision as of 08:31, 2 August 2021

Summary

Screenshot from IntelliJ IDEA 2021.2 Community Edition on Windows 10