Skip to content

Commit b584d9d

Browse files
committed
Add TypeScript proxy to support debugging with Chrome DevTools
Basic debugging features of step over, step in , step out, continue, stop, add/remove breakpoints, provide backtrace at breakpoint, and evaluate watch expressions are all working. A few low-hanging features still missing: - passthrough of output to CDT console - reporting exceptions - verbosity control Other features of CDT will require enhancement to JrS debugger, e.g.: - scope chain - inspectable eval output (e.g. JSON, not just strings) - memory analysis - profiling Significant level of unit testing provided via jest. Thanks to Martijn The <martijn.the@intel.com> for initial TS code skeleton, some unit tests, 'step out' feature, and tons of review! JerryScript-DCO-1.0-Signed-off-by: Geoff Gustafson geoff@linux.intel.com
1 parent 8392eef commit b584d9d

26 files changed

Lines changed: 6579 additions & 0 deletions

.travis.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,20 @@ matrix:
7070
- gcc-5-multilib
7171
env: OPTS="--quiet --jerry-tests --jerry-test-suite --skip-list=parser-oom.js --buildoptions=--compile-flag=-fsanitize=undefined,--compile-flag=-m32,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--debug,--jerry-libc=off,--static-link=off,--system-allocator=on,--linker-flag=-fuse-ld=gold" UBSAN_OPTIONS=print_stacktrace=1 TIMEOUT=600
7272

73+
- env: JOBNAME="JerryScript debugger TS client library"
74+
language: node_js
75+
node_js:
76+
- "9"
77+
cache: yarn
78+
before_install:
79+
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.5.1
80+
- export PATH="$HOME/.yarn/bin:$PATH"
81+
before_script:
82+
- "cd jerry-debugger/jerry-client-ts"
83+
script:
84+
- yarn
85+
- yarn lint
86+
- yarn test
7387
- env: JOBNAME="ESP8266 Build Test"
7488
cache: ccache
7589
install: make -f ./targets/esp8266/Makefile.travis install
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
dist
2+
node_modules
3+
src/coverage
4+
yarn-error.log
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# JerryScript Debugger
2+
3+
## Dependencies
4+
5+
- node.js
6+
- `yarn` or `npm` (the steps below use `yarn`)
7+
8+
## Installing
9+
10+
```
11+
$ cd jerryscript/jerry-debugger/jerry-client-ts
12+
$ yarn install
13+
```
14+
15+
## Using
16+
17+
TODO! We need to write the code first :D
18+
We're aiming for a CLI that is the same as `node`'s so that any IDE that can interact with `node` to debug .js code, can interact with the JerryScript debugger.
19+
20+
## Building in watch mode
21+
22+
This will make the TypeScript compiler monitor the source files and re-build files whenever there is a change.
23+
24+
```
25+
$ cd jerryscript/jerry-debugger/jerry-client-ts
26+
$ yarn build:watch
27+
```
28+
29+
## Running tests
30+
31+
```
32+
$ cd jerryscript/jerry-debugger/jerry-client-ts
33+
$ yarn test
34+
```
35+
36+
## Running tests in watch mode
37+
38+
This will make the test runner monitor the source files and re-run the tests whenever there is a change.
39+
40+
```
41+
$ cd jerryscript/jerry-debugger/jerry-client-ts
42+
$ yarn test:watch
43+
```
44+
45+
## Running the linter
46+
47+
```
48+
$ cd jerryscript/jerry-debugger/jerry-client-ts
49+
$ yarn lint
50+
```
51+
52+
## TODO
53+
54+
- Hook up build + test + lint into travis.yml
55+
- Fix "bin" files in package.json to get rid of jerry-debugger.sh
56+
- Tons of work
57+
- Set up publishing to npm
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
6+
node $DIR/dist/cli/index.js $@
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"name": "@jerryscript/debugger",
3+
"version": "0.0.1",
4+
"description": "Debugger for JerryScript",
5+
"bin": {
6+
"jerry-debugger": "dist/cli/index.js"
7+
},
8+
"main": "dist/index.js",
9+
"scripts": {
10+
"prepare": "tsc",
11+
"build": "tsc",
12+
"build:watch": "tsc --watch",
13+
"lint": "tslint -p .",
14+
"test": "jest",
15+
"test:watch": "jest --watch"
16+
},
17+
"repository": "https://github.com/jerryscript-project/jerryscript/",
18+
"author": "JS Foundation and other contributors",
19+
"license": "Apache-2.0",
20+
"private": false,
21+
"dependencies": {
22+
"chrome-remote-debug-protocol": "^1.2.20170721",
23+
"commander": "^2.15.0",
24+
"noice-json-rpc": "^1.1.1",
25+
"uuid": "^3.2.1",
26+
"ws": "^3.3.2"
27+
},
28+
"devDependencies": {
29+
"@types/commander": "^2.12.2",
30+
"@types/jest": "^22.1.2",
31+
"@types/minimist": "^1.2.0",
32+
"@types/node": "^9.4.6",
33+
"@types/uuid": "^3.4.3",
34+
"@types/ws": "^4.0.1",
35+
"jest": "^22.3.0",
36+
"ts-jest": "^22.0.4",
37+
"tslint": "^5.9.1",
38+
"tslint-config-standard": "^7.0.0",
39+
"typescript": "^2.7.1"
40+
},
41+
"jest": {
42+
"transform": {
43+
"^.+\\.tsx?$": "ts-jest"
44+
},
45+
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
46+
"moduleFileExtensions": [
47+
"ts",
48+
"tsx",
49+
"js",
50+
"jsx",
51+
"json",
52+
"node"
53+
],
54+
"globals": {
55+
"ts-jest": {
56+
"enableTsDiagnostics": true
57+
}
58+
},
59+
"rootDir": "src",
60+
"resetMocks": true,
61+
"resetModules": true
62+
}
63+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Copyright JS Foundation and other contributors, http://js.foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import { getOptionsFromArgs } from '../cli';
16+
import {
17+
DEFAULT_DEBUGGER_HOST,
18+
DEFAULT_DEBUGGER_PORT,
19+
} from '../../lib/debugger-client';
20+
import {
21+
DEFAULT_SERVER_HOST,
22+
DEFAULT_SERVER_PORT,
23+
} from '../../lib/cdt-proxy';
24+
25+
describe('getOptionsFromArgs', () => {
26+
27+
function getOptionsFromUserArgs(userArgs: string[]) {
28+
return getOptionsFromArgs(['node', 'jerry-debugger.js'].concat(userArgs));
29+
}
30+
31+
it('works without --inspect-brk', () => {
32+
const opt = getOptionsFromUserArgs([]);
33+
expect(opt.proxyAddress.host).toEqual(DEFAULT_SERVER_HOST);
34+
expect(opt.proxyAddress.port).toEqual(DEFAULT_SERVER_PORT);
35+
});
36+
37+
it('parses --inspect-brk with port only', () => {
38+
const opt = getOptionsFromUserArgs(['--inspect-brk=1234']);
39+
expect(opt.proxyAddress.host).toEqual(undefined);
40+
expect(opt.proxyAddress.port).toEqual(1234);
41+
});
42+
43+
it('parses --inspect-brk with no port', () => {
44+
const opt = getOptionsFromUserArgs(['--inspect-brk=10.10.10.10:']);
45+
expect(opt.proxyAddress.host).toEqual('10.10.10.10');
46+
expect(opt.proxyAddress.port).toEqual(undefined);
47+
});
48+
49+
it('parses --inspect-brk with no host', () => {
50+
const opt = getOptionsFromUserArgs(['--inspect-brk=:1234']);
51+
expect(opt.proxyAddress.host).toEqual(undefined);
52+
expect(opt.proxyAddress.port).toEqual(1234);
53+
});
54+
55+
it('parses --inspect-brk with host and port', () => {
56+
const opt = getOptionsFromUserArgs(['--inspect-brk=10.10.10.10:1234']);
57+
expect(opt.proxyAddress.host).toEqual('10.10.10.10');
58+
expect(opt.proxyAddress.port).toEqual(1234);
59+
});
60+
61+
it('works without --jerry-remote', () => {
62+
const opt = getOptionsFromUserArgs([]);
63+
expect(opt.remoteAddress.host).toEqual(DEFAULT_DEBUGGER_HOST);
64+
expect(opt.remoteAddress.port).toEqual(DEFAULT_DEBUGGER_PORT);
65+
});
66+
67+
it('parses --jerry-remote with port only', () => {
68+
const opt = getOptionsFromUserArgs(['--jerry-remote=1234']);
69+
expect(opt.remoteAddress.host).toEqual(undefined);
70+
expect(opt.remoteAddress.port).toEqual(1234);
71+
});
72+
73+
it('parses --jerry-remote with host and port', () => {
74+
const opt = getOptionsFromUserArgs(['--jerry-remote=10.10.10.10:1234']);
75+
expect(opt.remoteAddress.host).toEqual('10.10.10.10');
76+
expect(opt.remoteAddress.port).toEqual(1234);
77+
});
78+
79+
it('verbose defaults to false', () => {
80+
const opt = getOptionsFromUserArgs([]);
81+
expect(opt.verbose).toEqual(false);
82+
});
83+
84+
it('parses verbose flag', () => {
85+
const opt = getOptionsFromUserArgs(['--verbose']);
86+
expect(opt.verbose).toEqual(true);
87+
});
88+
89+
it('parses v alias for verbose', () => {
90+
const opt = getOptionsFromUserArgs(['-v']);
91+
expect(opt.verbose).toEqual(true);
92+
});
93+
94+
it('jsfile defaults to untitled.js', () => {
95+
const opt = getOptionsFromUserArgs([]);
96+
expect(opt.jsfile).toEqual('untitled.js');
97+
});
98+
99+
it('returns client source as jsfile', () => {
100+
const opt = getOptionsFromUserArgs(['foo/bar.js']);
101+
expect(opt.jsfile).toEqual('foo/bar.js');
102+
});
103+
104+
});
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright JS Foundation and other contributors, http://js.foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import { CDTController } from '../lib/cdt-controller';
16+
import {
17+
ChromeDevToolsProxyServer,
18+
DEFAULT_SERVER_HOST,
19+
DEFAULT_SERVER_PORT,
20+
} from '../lib/cdt-proxy';
21+
import {
22+
JerryDebuggerClient,
23+
DEFAULT_DEBUGGER_HOST,
24+
DEFAULT_DEBUGGER_PORT,
25+
} from '../lib/debugger-client';
26+
import { Command } from 'commander';
27+
import { JerryDebugProtocolHandler } from '../lib/protocol-handler';
28+
29+
/**
30+
* Converts string of format [host:][port] to an object with host and port,
31+
* each possibly undefined
32+
*/
33+
function getHostAndPort(input: string) {
34+
const hostAndPort = input.split(':');
35+
const portIndex = hostAndPort.length - 1;
36+
const host = hostAndPort[portIndex - 1];
37+
const port = hostAndPort[portIndex];
38+
return {
39+
host: host ? host : undefined,
40+
port: port ? Number(port) : undefined,
41+
};
42+
}
43+
44+
export function getOptionsFromArgs(argv: Array<string>) {
45+
const program = new Command('jerry-debugger');
46+
program
47+
.usage('[options] <script.js ...>')
48+
.option(
49+
'-v, --verbose',
50+
'Enable verbose logging', false)
51+
.option(
52+
'--inspect-brk [[host:]port]',
53+
'Activate Chrome DevTools proxy on host:port',
54+
`${DEFAULT_SERVER_HOST}:${DEFAULT_SERVER_PORT}`)
55+
.option(
56+
'--jerry-remote [[host:]port]',
57+
'Connect to JerryScript on host:port',
58+
`${DEFAULT_DEBUGGER_HOST}:${DEFAULT_DEBUGGER_PORT}`)
59+
.parse(argv);
60+
61+
return {
62+
proxyAddress: getHostAndPort(program.inspectBrk),
63+
remoteAddress: getHostAndPort(program.jerryRemote),
64+
jsfile: program.args[0] || 'untitled.js',
65+
verbose: program.verbose || false,
66+
};
67+
}
68+
69+
export function main(proc: NodeJS.Process) {
70+
const options = getOptionsFromArgs(proc.argv);
71+
72+
const controller = new CDTController();
73+
const jhandler = new JerryDebugProtocolHandler(controller);
74+
const jclient = new JerryDebuggerClient({
75+
delegate: jhandler,
76+
...options.remoteAddress,
77+
});
78+
jhandler.debuggerClient = jclient;
79+
// set this before connecting to the client
80+
controller.protocolHandler = jhandler;
81+
82+
const debuggerUrl = `ws://${jclient.host}:${jclient.port}`;
83+
jclient.connect().then(() => {
84+
console.log(`Connected to debugger at ${debuggerUrl}`);
85+
const proxy = new ChromeDevToolsProxyServer({
86+
delegate: controller,
87+
...options.proxyAddress,
88+
jsfile: options.jsfile,
89+
});
90+
// set this before making further debugger calls
91+
controller.proxyServer = proxy;
92+
console.log(`Proxy listening at ws://${proxy.host}:${proxy.port}`);
93+
}).catch((err) => {
94+
console.log(`Error connecting to debugger at ${debuggerUrl}`);
95+
console.log(err);
96+
});
97+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright JS Foundation and other contributors, http://js.foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import { main } from './cli';
16+
17+
main(process);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright JS Foundation and other contributors, http://js.foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// TODO: re-export more things here from lib/ that we want to expose as 'API'
16+
17+
export { ChromeDevToolsProxyServer } from './lib/cdt-proxy';

0 commit comments

Comments
 (0)