Skip to content

Commit

Permalink
feat(sdk): regex.match (#4039)
Browse files Browse the repository at this point in the history
An implementation to have regex introduced into Winglang
Motivation 
[first step to Add Regex type to String.replace() #3644 ]
Solution 
I have implemented regex match function by using the match in Javascript. 
It takes in the userString and regexPattern string (example below) and returns a true if they match ; false otherwise. 
 
```
let userString   = "peach";
let regexPattern =  "p[a-z]+h";
let matches      = userString.match(regexPattern); 
assert(matches == true);
```
It returns a boolean value of true or false.

 ## Checklist

- [ ] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted)
- [ ] Description explains motivation and solution
- [ ] Tests added (always)
- [ ] Docs updated (only required for features)
- [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing

*By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
  • Loading branch information
harsh9607 authored Aug 31, 2023
1 parent 33165cf commit 8cad1fa
Show file tree
Hide file tree
Showing 7 changed files with 336 additions and 1 deletion.
62 changes: 62 additions & 0 deletions examples/tests/sdk_tests/regex/match.w
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
bring regex;

let matches1 = regex.match("p[a-z]+ch" , "peach");
let matches2 = regex.match("[0-9]+" , "0923");
let matches3 = regex.match("[0-9]+" , "0a923");
let matches4 = regex.match("^([a-zA-Z0-9_.-]+)@[a-z]+.[a-z]+\$" , "[email protected]");

let matches5 = regex.match("p([a-z]+)ch" , "leach");
let matches6 = regex.match("^([a-zA-Z0-9_.-]+)@[a-z]+.[a-z]+" , "@[email protected]");

let matches7 = regex.match("^Mary" , "Mary had a little lamb");
let matches8 = regex.match("lamb\$" , "Mary had a little lamb");

let matches9 = regex.match("lamb\$" , "Mary had a little hamb");
let matches10 = regex.match("^([a-zA-Z0-9_.-]+)@[a-z]+.[a-z]+\$" , "[email protected]");

assert(matches1 == true );
assert(matches2 == true );
assert(matches3 == true );
assert(matches4 == true );

assert(matches5 == false);
assert(matches6 == false);

assert(matches7 == true );
assert(matches8 == true );

assert(matches9 == false);
assert(matches10 == false);

test "inflight match" {

let matches1 = regex.match("p[a-z]+ch" , "peach");
let matches2 = regex.match("[0-9]+" , "0923");
let matches3 = regex.match("[0-9]+" , "0a923");
let matches4 = regex.match("^([a-zA-Z0-9_.-]+)@[a-z]+.[a-z]+\$" , "[email protected]");

let matches5 = regex.match("p([a-z]+)ch" , "leach");
let matches6 = regex.match("^([a-zA-Z0-9_.-]+)@[a-z]+.[a-z]+" , "@[email protected]");

let matches7 = regex.match("^Mary" , "Mary had a little lamb");
let matches8 = regex.match("lamb\$" , "Mary had a little lamb");

let matches9 = regex.match("lamb\$" , "Mary had a little hamb");
let matches10 = regex.match("^([a-zA-Z0-9_.-]+)@[a-z]+.[a-z]+\$" , "[email protected]");


assert(matches1 == true );
assert(matches2 == true );
assert(matches3 == true );
assert(matches4 == true );

assert(matches5 == false);
assert(matches6 == false);

assert(matches7 == true );
assert(matches8 == true );

assert(matches9 == false);
assert(matches10 == false);

}
4 changes: 3 additions & 1 deletion libs/wingc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,16 @@ const WINGSDK_HTTP_MODULE: &'static str = "http";
const WINGSDK_MATH_MODULE: &'static str = "math";
const WINGSDK_AWS_MODULE: &'static str = "aws";
const WINGSDK_EX_MODULE: &'static str = "ex";
const WINGSDK_REGEX_MODULE: &'static str = "regex";

const WINGSDK_BRINGABLE_MODULES: [&'static str; 6] = [
const WINGSDK_BRINGABLE_MODULES: [&'static str; 7] = [
WINGSDK_CLOUD_MODULE,
WINGSDK_UTIL_MODULE,
WINGSDK_HTTP_MODULE,
WINGSDK_MATH_MODULE,
WINGSDK_AWS_MODULE,
WINGSDK_EX_MODULE,
WINGSDK_REGEX_MODULE,
];

const WINGSDK_DURATION: &'static str = "std.Duration";
Expand Down
1 change: 1 addition & 0 deletions libs/wingsdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * as core from "./core";
export * as ex from "./ex";
export * as http from "./http";
export * as math from "./math";
export * as regex from "./regex";
export * as aws from "./shared-aws";
export * as std from "./std";
export * as testing from "./testing";
Expand Down
1 change: 1 addition & 0 deletions libs/wingsdk/src/regex/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./regex";
28 changes: 28 additions & 0 deletions libs/wingsdk/src/regex/regex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { InflightClient } from "../core";

/**
* Regex utilities and functions
*/
export class Util {
/**
* Check if a regex pattern is matched by a given string
* @param pattern - regex pattern
* @param text - given input string
* @returns true if it matches the pattern, false otherwise
*/
public static match(pattern: string, text: string): boolean {
const regex = new RegExp(pattern);
if (text.match(regex) === null) {
return false;
}
return true;
}

/**
* @internal
*/
public static _toInflightType(): string {
return InflightClient.forType(__filename, this.name);
}
private constructor() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
# [match.w](../../../../../../examples/tests/sdk_tests/regex/match.w) | compile | tf-aws

## inflight.$Closure1-1.js
```js
module.exports = function({ $regex_Util }) {
class $Closure1 {
constructor({ }) {
const $obj = (...args) => this.handle(...args);
Object.setPrototypeOf($obj, this);
return $obj;
}
async handle() {
const matches1 = (await $regex_Util.match("p[a-z]+ch","peach"));
const matches2 = (await $regex_Util.match("[0-9]+","0923"));
const matches3 = (await $regex_Util.match("[0-9]+","0a923"));
const matches4 = (await $regex_Util.match("^([a-zA-Z0-9_.-]+)@[a-z]+.[a-z]+\$","[email protected]"));
const matches5 = (await $regex_Util.match("p([a-z]+)ch","leach"));
const matches6 = (await $regex_Util.match("^([a-zA-Z0-9_.-]+)@[a-z]+.[a-z]+","@[email protected]"));
const matches7 = (await $regex_Util.match("^Mary","Mary had a little lamb"));
const matches8 = (await $regex_Util.match("lamb\$","Mary had a little lamb"));
const matches9 = (await $regex_Util.match("lamb\$","Mary had a little hamb"));
const matches10 = (await $regex_Util.match("^([a-zA-Z0-9_.-]+)@[a-z]+.[a-z]+\$","[email protected]"));
{((cond) => {if (!cond) throw new Error("assertion failed: matches1 == true ")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches1,true)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches2 == true ")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches2,true)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches3 == true ")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches3,true)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches4 == true ")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches4,true)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches5 == false")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches5,false)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches6 == false")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches6,false)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches7 == true ")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches7,true)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches8 == true ")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches8,true)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches9 == false")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches9,false)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches10 == false")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches10,false)))};
}
}
return $Closure1;
}

```

## main.tf.json
```json
{
"//": {
"metadata": {
"backend": "local",
"stackName": "root",
"version": "0.17.0"
},
"outputs": {
"root": {
"Default": {
"cloud.TestRunner": {
"TestFunctionArns": "WING_TEST_RUNNER_FUNCTION_ARNS"
}
}
}
}
},
"output": {
"WING_TEST_RUNNER_FUNCTION_ARNS": {
"value": "[[\"root/Default/Default/test:inflight match\",\"${aws_lambda_function.testinflightmatch_Handler_91AFEF4E.arn}\"]]"
}
},
"provider": {
"aws": [
{}
]
},
"resource": {
"aws_iam_role": {
"testinflightmatch_Handler_IamRole_DA813D38": {
"//": {
"metadata": {
"path": "root/Default/Default/test:inflight match/Handler/IamRole",
"uniqueId": "testinflightmatch_Handler_IamRole_DA813D38"
}
},
"assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"},\"Effect\":\"Allow\"}]}"
}
},
"aws_iam_role_policy": {
"testinflightmatch_Handler_IamRolePolicy_B7F9EB14": {
"//": {
"metadata": {
"path": "root/Default/Default/test:inflight match/Handler/IamRolePolicy",
"uniqueId": "testinflightmatch_Handler_IamRolePolicy_B7F9EB14"
}
},
"policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"none:null\",\"Resource\":\"*\"}]}",
"role": "${aws_iam_role.testinflightmatch_Handler_IamRole_DA813D38.name}"
}
},
"aws_iam_role_policy_attachment": {
"testinflightmatch_Handler_IamRolePolicyAttachment_B8D01B6A": {
"//": {
"metadata": {
"path": "root/Default/Default/test:inflight match/Handler/IamRolePolicyAttachment",
"uniqueId": "testinflightmatch_Handler_IamRolePolicyAttachment_B8D01B6A"
}
},
"policy_arn": "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
"role": "${aws_iam_role.testinflightmatch_Handler_IamRole_DA813D38.name}"
}
},
"aws_lambda_function": {
"testinflightmatch_Handler_91AFEF4E": {
"//": {
"metadata": {
"path": "root/Default/Default/test:inflight match/Handler/Default",
"uniqueId": "testinflightmatch_Handler_91AFEF4E"
}
},
"architectures": [
"arm64"
],
"environment": {
"variables": {
"WING_FUNCTION_NAME": "Handler-c8aa61ca",
"WING_TARGET": "tf-aws"
}
},
"function_name": "Handler-c8aa61ca",
"handler": "index.handler",
"publish": true,
"role": "${aws_iam_role.testinflightmatch_Handler_IamRole_DA813D38.arn}",
"runtime": "nodejs18.x",
"s3_bucket": "${aws_s3_bucket.Code.bucket}",
"s3_key": "${aws_s3_object.testinflightmatch_Handler_S3Object_2184865C.key}",
"timeout": 30,
"vpc_config": {
"security_group_ids": [],
"subnet_ids": []
}
}
},
"aws_s3_bucket": {
"Code": {
"//": {
"metadata": {
"path": "root/Default/Code",
"uniqueId": "Code"
}
},
"bucket_prefix": "code-c84a50b1-"
}
},
"aws_s3_object": {
"testinflightmatch_Handler_S3Object_2184865C": {
"//": {
"metadata": {
"path": "root/Default/Default/test:inflight match/Handler/S3Object",
"uniqueId": "testinflightmatch_Handler_S3Object_2184865C"
}
},
"bucket": "${aws_s3_bucket.Code.bucket}",
"key": "<ASSET_KEY>",
"source": "<ASSET_SOURCE>"
}
}
}
}
```

## preflight.js
```js
const $stdlib = require('@winglang/sdk');
const $plugins = ((s) => !s ? [] : s.split(';'))(process.env.WING_PLUGIN_PATHS);
const $outdir = process.env.WING_SYNTH_DIR ?? ".";
const $wing_is_test = process.env.WING_IS_TEST === "true";
const std = $stdlib.std;
const regex = $stdlib.regex;
class $Root extends $stdlib.std.Resource {
constructor(scope, id) {
super(scope, id);
class $Closure1 extends $stdlib.std.Resource {
constructor(scope, id, ) {
super(scope, id);
(std.Node.of(this)).hidden = true;
}
static _toInflightType(context) {
return `
require("./inflight.$Closure1-1.js")({
$regex_Util: ${context._lift(regex.Util)},
})
`;
}
_toInflight() {
return `
(await (async () => {
const $Closure1Client = ${$Closure1._toInflightType(this)};
const client = new $Closure1Client({
});
if (client.$inflight_init) { await client.$inflight_init(); }
return client;
})())
`;
}
_getInflightOps() {
return ["handle", "$inflight_init"];
}
}
const matches1 = (regex.Util.match("p[a-z]+ch","peach"));
const matches2 = (regex.Util.match("[0-9]+","0923"));
const matches3 = (regex.Util.match("[0-9]+","0a923"));
const matches4 = (regex.Util.match("^([a-zA-Z0-9_.-]+)@[a-z]+.[a-z]+\$","[email protected]"));
const matches5 = (regex.Util.match("p([a-z]+)ch","leach"));
const matches6 = (regex.Util.match("^([a-zA-Z0-9_.-]+)@[a-z]+.[a-z]+","@[email protected]"));
const matches7 = (regex.Util.match("^Mary","Mary had a little lamb"));
const matches8 = (regex.Util.match("lamb\$","Mary had a little lamb"));
const matches9 = (regex.Util.match("lamb\$","Mary had a little hamb"));
const matches10 = (regex.Util.match("^([a-zA-Z0-9_.-]+)@[a-z]+.[a-z]+\$","[email protected]"));
{((cond) => {if (!cond) throw new Error("assertion failed: matches1 == true ")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches1,true)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches2 == true ")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches2,true)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches3 == true ")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches3,true)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches4 == true ")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches4,true)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches5 == false")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches5,false)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches6 == false")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches6,false)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches7 == true ")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches7,true)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches8 == true ")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches8,true)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches9 == false")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches9,false)))};
{((cond) => {if (!cond) throw new Error("assertion failed: matches10 == false")})((((a,b) => { try { return require('assert').deepStrictEqual(a,b) === undefined; } catch { return false; } })(matches10,false)))};
this.node.root.new("@winglang/sdk.std.Test",std.Test,this,"test:inflight match",new $Closure1(this,"$Closure1"));
}
}
const $App = $stdlib.core.App.for(process.env.WING_TARGET);
new $App({ outdir: $outdir, name: "match", rootConstruct: $Root, plugins: $plugins, isTestEnvironment: $wing_is_test, entrypointDir: process.env['WING_SOURCE_DIR'], rootId: process.env['WING_ROOT_ID'] }).synth();

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# [match.w](../../../../../../examples/tests/sdk_tests/regex/match.w) | test | sim

## stdout.log
```log
pass ─ match.wsim » root/env0/test:inflight match
Tests 1 passed (1)
Test Files 1 passed (1)
Duration <DURATION>
```

0 comments on commit 8cad1fa

Please sign in to comment.