Skip to content

Commit

Permalink
Improvement for JS ecosystem (#2270)
Browse files Browse the repository at this point in the history
* Include a headers file in npm package so that ESM scripts can import the package, even if they can't run it

* Remove committed file

* Add function signatures for various user scripts
  • Loading branch information
gausie committed Apr 8, 2024
1 parent 3f1ac30 commit a60482e
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 31 deletions.
1 change: 1 addition & 0 deletions .github/npm/.gitignore
@@ -1,2 +1,3 @@
node_modules
index.d.ts
index.js
16 changes: 8 additions & 8 deletions .github/npm/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions .github/npm/package.json
Expand Up @@ -2,8 +2,8 @@
"name": "kolmafia",
"version": "{{version}}",
"description": "Typings for the KoLmafia JS standard library",
"main": "index",
"types": "index",
"main": "index.js",
"types": "index.d.ts",
"repository": "https://github.com/kolmafia/kolmafia",
"author": "KoLmafia Team",
"license": "MIT",
Expand All @@ -12,7 +12,7 @@
"index.d.ts"
],
"devDependencies": {
"typescript": "^4.8.4"
"typescript": "^5.4.4"
},
"scripts": {
"validate": "tsc ./index.d.ts"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/npm.yml
Expand Up @@ -34,7 +34,6 @@ jobs:

- name: Checking generated TypeScript definitions
run: |
mv index.d.ts .github/npm/index.d.ts
cd .github/npm
npm install
npm run validate
Expand All @@ -43,6 +42,7 @@ jobs:
run: |
PACKAGE_VERSION=$(head -n 1 .github/npm/index.d.ts | cut -c 5-)
sed -i 's/{{version}}/'$PACKAGE_VERSION'/g' .github/npm/package.json
sed -i 's/{{version}}/'$PACKAGE_VERSION'/g' .github/npm/package-json.json
- name: Publishing TypeScript package to npm
run: |
Expand Down
89 changes: 72 additions & 17 deletions src/net/sourceforge/kolmafia/textui/TypescriptDefinition.java
Expand Up @@ -21,6 +21,7 @@
import net.sourceforge.kolmafia.textui.parsetree.Function;
import net.sourceforge.kolmafia.textui.parsetree.LibraryFunction;
import net.sourceforge.kolmafia.textui.parsetree.RecordType;
import net.sourceforge.kolmafia.textui.parsetree.Symbol;
import net.sourceforge.kolmafia.textui.parsetree.Type;
import net.sourceforge.kolmafia.textui.parsetree.VarArgType;
import net.sourceforge.kolmafia.textui.parsetree.VariableReference;
Expand Down Expand Up @@ -155,12 +156,22 @@ public static String formatFunction(LibraryFunction f) {
return String.format("%sexport function %s(%s): %s;", deprecationWarning, name, params, type);
}

private static List<String> getFunctions() {
private static Stream<LibraryFunction> getFunctions() {
return JavascriptRuntime.getFunctions().stream()
.filter(f -> !f.getName().equals("delete"))
.filter(LibraryFunction.class::isInstance)
.map(LibraryFunction.class::cast)
.map(TypescriptDefinition::formatFunction)
.map(LibraryFunction.class::cast);
}

private static List<String> getFunctionDefinitions() {
return getFunctions().map(TypescriptDefinition::formatFunction).toList();
}

private static List<String> getFunctionHeaders() {
return getFunctions()
.map(Symbol::getName)
.distinct()
.map(f -> String.format("export const %s = warn;", JavascriptRuntime.toCamelCase(f)))
.toList();
}

Expand Down Expand Up @@ -253,7 +264,14 @@ private static List<String> formatMafiaClass(final Type t) {
return result;
}

private static List<String> getMafiaClasses() {
private static List<String> getMafiaClassHeaders() {
return DataTypes.enumeratedTypes.stream()
.map(t -> StringUtilities.capitalize(t.getName()))
.map(t -> String.format("export class %s {}", t))
.toList();
}

private static List<String> getMafiaClassDefs() {
return DataTypes.enumeratedTypes.stream()
.sorted(Type::compareTo)
.flatMap(t -> formatMafiaClass(t).stream())
Expand Down Expand Up @@ -326,13 +344,33 @@ protected static List<String> getFrontMatter() {
"// Generated by KoLmafia r" + kolmafiaVersion + " with type generator v" + VERSION);
}

public static String getContents() {
protected static List<String> getScriptFunctionDefs() {
return List.of(
"export type AfterAdventureScript = () => void;",
"export type BeforePVPScript = () => void;",
"export type BetweenBattleScript = () => void;",
"export type BuyScript = (item: string, quantity: string, ingredientLevel: string, defaultBuy: string) => boolean;",
"export type ChatPlayerScript = (playerName: string, playerId: string, channel: string) => void;",
"export type ChatbotScript = (sender: string, content: string, channel?: string) => void;",
"export type ChoiceAdventureScript = (choiceNumber: number, responseText: string) => void;",
"export type ConsultScript = (round: number, monster: Monster, responseText: string) => void;",
"export type CounterScript = (label: string, turnsRemaining: string) => boolean;",
"export type FamiliarScript = () => boolean;",
"export type KingLiberatedScript = () => void;",
"export type PostAscensionScript = () => void;",
"export type PreAscensionScript = () => void;",
"export type RecoveryScript = (type: \"HP\" | \"MP\", needed: number) => boolean;",
"export type SpadingScript = (event: string, meta: string, responseText: string) => void;");
}

public static String getTypeDefContents() {
return Stream.of(
getFrontMatter(),
getHelperTypes(),
getFunctions(),
getFunctionDefinitions(),
getAbstractMafiaClass(),
getMafiaClasses(),
getMafiaClassDefs(),
getScriptFunctionDefs(),
getSessionStorageTyping())
.flatMap(Collection::stream)
.collect(Collectors.joining("\n"));
Expand All @@ -346,19 +384,36 @@ private static String getVersion(final String[] args) {
return String.valueOf(StaticEntity.getRevision());
}

public static String getHeaderFileContents() {
return Stream.of(
List.of(
"const warn = () => { throw new Error(`Cannot access the KoLmafia standard library from a normal JavaScript context.`); }",
"export const sessionStorage = {};"),
getFunctionHeaders(),
getMafiaClassHeaders())
.flatMap(Collection::stream)
.collect(Collectors.joining("\n"));
}

public static void main(final String[] args) {
kolmafiaVersion = getVersion(args);

var contents = getContents();

try {
Files.write(
Path.of("./index.d.ts"),
contents.getBytes(),
StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.CREATE);
} catch (IOException e) {
System.out.println("Cannot write to index.d.ts");
var files =
List.of(
Map.entry("index.d.ts", getTypeDefContents()),
Map.entry("index.js", getHeaderFileContents()));

for (var entry : files) {
var file = entry.getKey();
try {
Files.write(
Path.of("./.github/npm/" + file),
entry.getValue().getBytes(),
StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.CREATE);
} catch (IOException e) {
System.out.println("Cannot write to " + file);
}
}
}
}
@@ -1,6 +1,7 @@
package net.sourceforge.kolmafia.textui;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
Expand Down Expand Up @@ -28,7 +29,7 @@ private LibraryFunction findFunction(final String signature) {

@Test
void producesAnyOutput() {
assertThat(TypescriptDefinition.getContents(), hasLength(greaterThan(0)));
assertThat(TypescriptDefinition.getTypeDefContents(), hasLength(greaterThan(0)));
}

private static Stream<Arguments> provideStringsForFormatFunction() {
Expand Down Expand Up @@ -67,7 +68,7 @@ void showsDeprecationMessage() {
void firstLineContainsValidVersionNumber() {
// We get the version number with `PACKAGE_VERSION=$(head -n 1 index.d.ts | cut -c 5-)`
// As such, here we test that this produces a valid version number
var contents = TypescriptDefinition.getContents();
var contents = TypescriptDefinition.getTypeDefContents();
var firstLine = contents.substring(0, contents.indexOf("\n"));
var version = firstLine.substring(4);
assertThat(version, matchesPattern("^\\d+\\.\\d+\\.\\d+$"));
Expand All @@ -77,4 +78,10 @@ void firstLineContainsValidVersionNumber() {
void containsEnvironmentUnion() {
assertThat(TypescriptDefinition.getEnvironmentUnion(), startsWith("\"indoor\""));
}

@Test
void headerFile() {
var contents = TypescriptDefinition.getHeaderFileContents();
assertThat(contents, containsString("export const visitUrl = "));
}
}

0 comments on commit a60482e

Please sign in to comment.