Skip to content

Commit

Permalink
Merge of #5967
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Mar 18, 2024
2 parents a361e81 + 953227a commit 4df2d9a
Show file tree
Hide file tree
Showing 34 changed files with 926 additions and 103 deletions.
68 changes: 35 additions & 33 deletions docs/docs/07-examples/10-using-javascript.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,58 @@
---
title: Using JavaScript
title: Using JavaScript/TypeScript
id: using-javascript
keywords: [Wing example]
keywords: [example, javascript, extern, typescript, js, ts]
---

Calling a Javascript function from Wing requires two steps.
Calling a Javascript function from Wing requires two steps.

First, export the function from Javascript.

This examples exports `isValidUrl` from a file named`url_utils.js`:
1. Create a .js file that exports some functions

```js
exports.isValidUrl = function(url) {
try {
new URL(url);
return true;
} catch {
return false;
}
// util.js

exports.isValidUrl = function (url) {
return URL.canParse(url);
};
```

### Preflight function

To call this in preflight code, define the function as an `extern` in a class.

**Note:** Extern functions must be `static.`
In preflight, this file must be a CommonJS module written in Javascript. Inflight, it may be CJS/ESM and either JavaScript or TypeScript.

If you want to use the function outside of the class, be sure to declare it as `pub`.
2. Use the `extern` keyword in a class to expose the function to Wing. Note that this must be `static`. It may also be `inflight`

```ts
class JsExample {
// preflight static
pub extern "./url_utils.js" static isValidUrl(url: str): bool;
```ts
class JsExample {
pub extern "./util.js" static isValidUrl(url: str): bool;
}

assert(JsExample.isValidUrl("http://www.google.com"));
assert(!JsExample.isValidUrl("X?Y"));
```

### Inflight
### Type-safe `extern`

To call the function inflight, add the `inflight` modifier.
Running `wing compile` will generate a corresponding `.d.ts` file for each `extern`. This file can be imported into the extern file itself to ensure the extern is type-safe. Either your IDE or a separate usage of the TypeScript compiler can provide type-checking.

```ts
class JsExample {
// inflight static method
extern "./url_utils.js" static inflight isValidUrl(url: str): bool;
}
// util.ts
import type extern from "./util.extern";

test "main" {
assert(JsExample.isValidUrl("http://www.google.com"));
assert(!JsExample.isValidUrl("X?Y"));
}
export const isValidUrl: extern["isValidUrl"] = (url) => {
// url is known to be a string and that we must return a boolean
return URL.canParse(url);
};
```

The .d.ts file can also be used in JavaScript via JSDoc comments and can even be applied at a module export level.

```js
// util.js
/** @type {import("./util.extern").default} */
module.exports = {
isValidUrl: (url) => {
return URL.canParse(url);
},
};
```

Coming Soon: The ability to use resources inside an `inflight extern`. See [this issue](https://github.com/winglang/wing/issues/76) for more information.
3 changes: 3 additions & 0 deletions examples/tests/sdk_tests/function/logging.extern.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default interface extern {
logging: () => Promise<void>,
}
10 changes: 10 additions & 0 deletions examples/tests/sdk_tests/service/http-server.extern.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default interface extern {
createServer: (body: string) => Promise<IHttpServer$Inflight>,
}
export interface Address {
readonly port: number;
}
export interface IHttpServer$Inflight {
readonly address: () => Promise<Address>;
readonly close: () => Promise<void>;
}
3 changes: 3 additions & 0 deletions examples/tests/sdk_tests/util/util.extern.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default interface extern {
platform: () => Promise<string>,
}
3 changes: 3 additions & 0 deletions examples/tests/sdk_tests/util/uuidv4-helper.extern.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default interface extern {
validateUUIDv4: (uuidv4: string) => Promise<boolean>,
}
8 changes: 2 additions & 6 deletions examples/tests/sdk_tests/util/uuidv4.test.w
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
bring util;

class JSHelper {
extern "./uuidv4-helper.js" pub static validateUUIDv4(uuidv4: str): bool;
}

let data = util.uuidv4();
assert(JSHelper.validateUUIDv4(data) == true);
let preflightData = util.uuidv4();

class JSHelperInflight {
extern "./uuidv4-helper.js" pub static inflight validateUUIDv4(uuidv4: str): bool;
Expand All @@ -14,4 +9,5 @@ class JSHelperInflight {
test "inflight uuidv4" {
let data = util.uuidv4();
assert(JSHelperInflight.validateUUIDv4(data) == true);
assert(JSHelperInflight.validateUUIDv4(preflightData) == true);
}
2 changes: 1 addition & 1 deletion examples/tests/valid/capture_tokens.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class MyResource {
api: cloud.Api;
url: str;

extern "./url_utils.js" pub static inflight isValidUrl(url: str): bool;
extern "./url_utils.ts" pub static inflight isValidUrl(url: str): bool;

new() {
this.api = new cloud.Api();
Expand Down
4 changes: 4 additions & 0 deletions examples/tests/valid/dynamo.extern.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default interface extern {
_getItem: (tableName: string, key: Readonly<any>) => Promise<Readonly<any>>,
_putItem: (tableName: string, item: Readonly<any>) => Promise<void>,
}
3 changes: 2 additions & 1 deletion examples/tests/valid/dynamo.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ class DynamoTable {
}
}

extern "./dynamo.js" static inflight _putItem(tableName: str, item: Json): void;
extern "./dynamo.ts" static inflight _getItem(tableName: str, key: Json): Json;
extern "./dynamo.ts" static inflight _putItem(tableName: str, item: Json): void;

pub inflight putItem(item: Map<Attribute>) {
let json = this._itemToJson(item);
Expand Down
17 changes: 11 additions & 6 deletions examples/tests/valid/dynamo.js → examples/tests/valid/dynamo.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
const { DynamoDBClient, PutItemCommand, GetItemCommand } = require("@aws-sdk/client-dynamodb");
import type extern from "./dynamo.extern";
import {
DynamoDBClient,
PutItemCommand,
GetItemCommand,
} from "@aws-sdk/client-dynamodb";

const client = new DynamoDBClient({});

export async function _putItem(tableName, item) {
export const _putItem: extern["_putItem"] = async (tableName, item) => {
const command = new PutItemCommand({
TableName: tableName,
Item: item,
Expand All @@ -11,15 +16,15 @@ export async function _putItem(tableName, item) {
const response = await client.send(command);
console.log(response);
return;
}
};

export async function _getItem(tableName, key) {
export const _getItem: extern["_getItem"] = async (tableName, key) => {
const command = new GetItemCommand({
TableName: tableName,
Key: key
Key: key,
});

const response = await client.send(command);
console.log(response);
return response;
}
};
4 changes: 2 additions & 2 deletions examples/tests/valid/dynamo_awscdk.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ class DynamoTable {
}
}

extern "./dynamo.js" static inflight _putItem(tableName: str, item: Json): void;
extern "./dynamo.ts" static inflight _putItem(tableName: str, item: Json): void;
pub inflight putItem(item: Map<Attribute>) {
let json = this._itemToJson(item);
DynamoTable._putItem(this.tableName, json);
}

extern "./dynamo.js" static inflight _getItem(tableName: str, key: Json): Json;
extern "./dynamo.ts" static inflight _getItem(tableName: str, key: Json): Json;
pub inflight getItem(key: Map<Attribute>): Json {
let json = this._itemToJson(key);
return DynamoTable._getItem(this.tableName, json);
Expand Down
4 changes: 4 additions & 0 deletions examples/tests/valid/extern_implementation.test.w
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Foo {
extern "./external_js.js" static inflight getUuid(): str;
extern "./external_js.js" static inflight getData(): str;
extern "./external_js.js" pub static inflight print(msg: str): void;
extern "./external_js.js" pub static preflightBucket(bucket: cloud.Bucket, id: str): Json;

pub inflight call() {
assert(Foo.regexInflight("[a-z]+-\\d+", "abc-123"));
Expand All @@ -20,6 +21,9 @@ assert(Foo.getGreeting("Wingding") == "Hello, Wingding!");

let f = new Foo();

let bucket = new cloud.Bucket() as "my-bucket";
let result = Foo.preflightBucket(bucket, "my-bucket");

test "call" {
f.call();
}
Expand Down
Loading

0 comments on commit 4df2d9a

Please sign in to comment.