Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge queue: embarking main (a361e81), #5967 and #5962 together #5974

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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
Loading