Skip to content

Commit db5ace9

Browse files
committed
adding parse
1 parent a05d1c4 commit db5ace9

File tree

8 files changed

+312
-0
lines changed

8 files changed

+312
-0
lines changed

packages/parse/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Hyperweb Parse
2+
3+
<p align="center" width="100%">
4+
<img src="https://raw.githubusercontent.com/hyperweb-io/.github/refs/heads/main/assets/logo.svg" alt="hyperweb" width="80"><br />
5+
</p>
6+
7+
<p align="center" width="100%">
8+
<a href="https://github.com/hyperweb-io/hyperweb-build/actions/workflows/run-tests.yml">
9+
<img height="20" src="https://github.com/hyperweb-io/hyperweb-build/actions/workflows/run-tests.yml/badge.svg" />
10+
</a>
11+
<br />
12+
<a href="https://github.com/hyperweb-io/hyperweb-build/blob/main/LICENSE"><img height="20" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
13+
<a href="https://www.npmjs.com/package/@hyperweb/build"><img height="20" src="https://img.shields.io/github/package-json/v/hyperweb-io/hyperweb-build?filename=packages%2Fbuild%2Fpackage.json"></a>
14+
</p>
15+
16+
17+
## Interchain JavaScript Stack
18+
19+
A unified toolkit for building applications and smart contracts in the Interchain ecosystem ⚛️
20+
21+
| Category | Tools | Description |
22+
|----------------------|------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------|
23+
| **Chain Information** | [**Chain Registry**](https://github.com/hyperweb-io/chain-registry), [**Utils**](https://www.npmjs.com/package/@chain-registry/utils), [**Client**](https://www.npmjs.com/package/@chain-registry/client) | Everything from token symbols, logos, and IBC denominations for all assets you want to support in your application. |
24+
| **Wallet Connectors**| [**Interchain Kit**](https://github.com/hyperweb-io/interchain-kit)<sup>beta</sup>, [**Cosmos Kit**](https://github.com/hyperweb-io/cosmos-kit) | Experience the convenience of connecting with a variety of web3 wallets through a single, streamlined interface. |
25+
| **Signing Clients** | [**InterchainJS**](https://github.com/hyperweb-io/interchainjs)<sup>beta</sup>, [**CosmJS**](https://github.com/cosmos/cosmjs) | A single, universal signing interface for any network |
26+
| **SDK Clients** | [**Telescope**](https://github.com/hyperweb-io/telescope) | Your Frontend Companion for Building with TypeScript with Cosmos SDK Modules. |
27+
| **Starter Kits** | [**Create Interchain App**](https://github.com/hyperweb-io/create-interchain-app)<sup>beta</sup>, [**Create Cosmos App**](https://github.com/hyperweb-io/create-cosmos-app) | Set up a modern Interchain app by running one command. |
28+
| **UI Kits** | [**Interchain UI**](https://github.com/hyperweb-io/interchain-ui) | The Interchain Design System, empowering developers with a flexible, easy-to-use UI kit. |
29+
| **Testing Frameworks** | [**Starship**](https://github.com/hyperweb-io/starship) | Unified Testing and Development for the Interchain. |
30+
| **TypeScript Smart Contracts** | [**Create Hyperweb App**](https://github.com/hyperweb-io/create-hyperweb-app) | Build and deploy full-stack blockchain applications with TypeScript |
31+
| **CosmWasm Contracts** | [**CosmWasm TS Codegen**](https://github.com/CosmWasm/ts-codegen) | Convert your CosmWasm smart contracts into dev-friendly TypeScript classes. |
32+
33+
## Credits
34+
35+
🛠 Built by Hyperweb (formerly Cosmology) — if you like our tools, please checkout and contribute to [our github ⚛️](https://github.com/hyperweb-io)
36+
37+
## Disclaimer
38+
39+
AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED “AS IS”, AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.
40+
41+
No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { ContractAnalyzer } from '../src/ContractAnalyzer';
2+
3+
describe('ContractAnalyzer', () => {
4+
let analyzer: ContractAnalyzer;
5+
6+
beforeEach(() => {
7+
analyzer = new ContractAnalyzer();
8+
});
9+
10+
it('should identify query methods', () => {
11+
const code = `
12+
class Contract {
13+
state: any;
14+
15+
getState() {
16+
return this.state;
17+
}
18+
19+
getValue() {
20+
const value = this.state.value;
21+
return value;
22+
}
23+
}
24+
`;
25+
26+
const result = analyzer.analyzeFromCode(code);
27+
expect(result.queries).toEqual(['getState', 'getValue']);
28+
expect(result.mutations).toEqual([]);
29+
});
30+
31+
it('should identify mutation methods', () => {
32+
const code = `
33+
class Contract {
34+
state: any;
35+
36+
setState(newState: any) {
37+
this.state = newState;
38+
}
39+
40+
updateValue(value: any) {
41+
this.state.value = value;
42+
}
43+
}
44+
`;
45+
46+
const result = analyzer.analyzeFromCode(code);
47+
expect(result.queries).toEqual([]);
48+
expect(result.mutations).toEqual(['setState', 'updateValue']);
49+
});
50+
51+
it('should identify both query and mutation methods', () => {
52+
const code = `
53+
class Contract {
54+
state: any;
55+
56+
getState() {
57+
return this.state;
58+
}
59+
60+
setState(newState: any) {
61+
this.state = newState;
62+
}
63+
64+
updateAndGet() {
65+
this.state.value = 42;
66+
return this.state.value;
67+
}
68+
}
69+
`;
70+
71+
const result = analyzer.analyzeFromCode(code);
72+
expect(result.queries).toEqual(['getState']);
73+
expect(result.mutations).toEqual(['setState', 'updateAndGet']);
74+
});
75+
76+
it('should ignore static methods and constructors', () => {
77+
const code = `
78+
class Contract {
79+
state: any;
80+
81+
constructor() {
82+
this.state = {};
83+
}
84+
85+
static getStaticState() {
86+
return this.state;
87+
}
88+
89+
getState() {
90+
return this.state;
91+
}
92+
}
93+
`;
94+
95+
const result = analyzer.analyzeFromCode(code);
96+
expect(result.queries).toEqual(['getState']);
97+
expect(result.mutations).toEqual([]);
98+
});
99+
});

packages/parse/jest.config.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/** @type {import('ts-jest').JestConfigWithTsJest} */
2+
module.exports = {
3+
preset: 'ts-jest',
4+
testEnvironment: 'node',
5+
transform: {
6+
'^.+\\.tsx?$': [
7+
'ts-jest',
8+
{
9+
babelConfig: false,
10+
tsconfig: 'tsconfig.json',
11+
},
12+
],
13+
},
14+
transformIgnorePatterns: [`/node_modules/*`],
15+
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$',
16+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
17+
modulePathIgnorePatterns: ['dist/*']
18+
};

packages/parse/package.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "@hyperweb/parse",
3+
"version": "1.0.1",
4+
"author": "Hyperweb <[email protected]>",
5+
"description": "Parse Hyperweb contracts",
6+
"main": "index.js",
7+
"module": "esm/index.js",
8+
"types": "index.d.ts",
9+
"homepage": "https://github.com/hyperweb-io/hyperweb-build",
10+
"license": "SEE LICENSE IN LICENSE",
11+
"publishConfig": {
12+
"access": "public",
13+
"directory": "dist"
14+
},
15+
"repository": {
16+
"type": "git",
17+
"url": "https://github.com/hyperweb-io/hyperweb-build"
18+
},
19+
"bugs": {
20+
"url": "https://github.com/hyperweb-io/hyperweb-build/issues"
21+
},
22+
"scripts": {
23+
"copy": "copyfiles -f ../../LICENSE README.md package.json dist",
24+
"clean": "rimraf dist/**",
25+
"prepare": "npm run build",
26+
"build": "npm run clean; tsc; tsc -p tsconfig.esm.json; npm run copy",
27+
"build:dev": "npm run clean; tsc --declarationMap; tsc -p tsconfig.esm.json; npm run copy",
28+
"lint": "eslint . --fix",
29+
"test": "jest",
30+
"test:watch": "jest --watch"
31+
},
32+
"keywords": [],
33+
"dependencies": {
34+
"@babel/parser": "^7.24.0",
35+
"@babel/traverse": "^7.24.0",
36+
"@babel/types": "^7.24.0"
37+
}
38+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import * as parser from '@babel/parser';
2+
import traverse from '@babel/traverse';
3+
import * as t from '@babel/types';
4+
5+
export interface AnalysisResult {
6+
queries: string[];
7+
mutations: string[];
8+
}
9+
10+
export class ContractAnalyzer {
11+
private ast: parser.ParseResult<t.File> | null = null;
12+
13+
/**
14+
* Analyzes a TypeScript contract class to identify query and mutation methods
15+
* @param code The TypeScript source code to analyze
16+
* @returns An object containing arrays of query and mutation method names
17+
*/
18+
public analyzeFromCode(code: string): AnalysisResult {
19+
this.parseCode(code);
20+
return this.analyze();
21+
}
22+
23+
/**
24+
* Parses the TypeScript code into an AST
25+
* @param code The TypeScript source code to parse
26+
*/
27+
private parseCode(code: string): void {
28+
this.ast = parser.parse(code, {
29+
sourceType: 'module',
30+
plugins: ['typescript', 'classProperties', 'decorators-legacy'],
31+
});
32+
}
33+
34+
/**
35+
* Analyzes the parsed AST to identify query and mutation methods
36+
* @returns An object containing arrays of query and mutation method names
37+
*/
38+
private analyze(): AnalysisResult {
39+
if (!this.ast) {
40+
throw new Error('No code has been parsed. Call analyzeFromCode first.');
41+
}
42+
43+
const queries: string[] = [];
44+
const mutations: string[] = [];
45+
46+
traverse(this.ast, {
47+
ClassMethod(path) {
48+
// Skip static methods and constructors
49+
if (path.node.static || path.node.kind === 'constructor') {
50+
return;
51+
}
52+
53+
const methodName = path.node.key.type === 'Identifier' ? path.node.key.name : '';
54+
if (!methodName) return;
55+
56+
let readsState = false;
57+
let writesState = false;
58+
59+
// Check for state access
60+
path.traverse({
61+
MemberExpression(memberPath) {
62+
const object = memberPath.node.object;
63+
const property = memberPath.node.property;
64+
65+
// Check if this is a this.state access
66+
if (
67+
t.isThisExpression(object) &&
68+
t.isIdentifier(property) &&
69+
property.name === 'state'
70+
) {
71+
// Check if this is part of an assignment
72+
const parent = memberPath.parentPath;
73+
if (
74+
t.isAssignmentExpression(parent.node) ||
75+
(t.isMemberExpression(parent.node) &&
76+
t.isAssignmentExpression(parent.parentPath.node))
77+
) {
78+
writesState = true;
79+
} else {
80+
readsState = true;
81+
}
82+
}
83+
},
84+
});
85+
86+
// If a method writes to state, it's a mutation
87+
// If it only reads from state, it's a query
88+
if (writesState) {
89+
mutations.push(methodName);
90+
} else if (readsState) {
91+
queries.push(methodName);
92+
}
93+
},
94+
});
95+
96+
return { queries, mutations };
97+
}
98+
}

packages/parse/src/index.ts

Whitespace-only changes.

packages/parse/tsconfig.esm.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"outDir": "dist/esm",
5+
"module": "es2022",
6+
"rootDir": "src/",
7+
"declaration": false
8+
}
9+
}

packages/parse/tsconfig.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"compilerOptions": {
4+
"outDir": "dist",
5+
"rootDir": "src/"
6+
},
7+
"include": ["src/**/*.ts"],
8+
"exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"]
9+
}

0 commit comments

Comments
 (0)