├── tests ├── micro │ ├── node_modules │ │ ├── rxjs │ │ │ ├── Rx.js │ │ │ └── package.json │ │ ├── node-exports │ │ │ ├── index.mjs │ │ │ ├── index.js │ │ │ └── package.json │ │ └── library │ │ │ ├── index.js │ │ │ └── package.json │ ├── twoversions │ │ ├── package.json │ │ ├── index.js │ │ └── node_modules │ │ │ ├── boxen │ │ │ ├── index.js │ │ │ ├── node_modules │ │ │ │ └── ansi-regex │ │ │ │ │ ├── index.js │ │ │ │ │ └── package.json │ │ │ └── package.json │ │ │ └── ansi-regex │ │ │ ├── index.js │ │ │ └── package.json │ ├── undecl2.js │ ├── lib6.js │ ├── call.js │ ├── export10.mjs │ ├── sub │ │ └── index.js │ ├── undecl1.js │ ├── client6.js │ ├── packagejson │ │ ├── index.js │ │ ├── node_modules │ │ │ └── terser │ │ │ │ ├── dist │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ │ └── package.json │ │ ├── patterns.json │ │ └── package.json │ ├── client8.js │ ├── flow.js │ ├── import7.mjs │ ├── import10.mjs │ ├── import12.mjs │ ├── bind.js │ ├── globals │ │ ├── sample │ │ │ ├── app.js │ │ │ └── package.json │ │ ├── package.json │ │ └── lib1 │ │ │ └── lib.js │ ├── lib10.mjs │ ├── import-default │ │ ├── b.d.ts │ │ ├── a.ts │ │ ├── b.js │ │ ├── package.json │ │ └── tsconfig.json │ ├── lib3.js │ ├── package.json │ ├── client3.js │ ├── packagealias │ │ ├── node_modules │ │ │ ├── set-value │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ └── merge-value-alias │ │ │ │ ├── package.json │ │ │ │ └── index.js │ │ ├── index.js │ │ └── package.json │ ├── peerdep │ │ ├── peerdep.js │ │ ├── peerdep-patterns.json │ │ └── package.json │ ├── import9.mjs │ ├── date.js │ ├── export3b.mjs │ ├── export9.mjs │ ├── externmap.js │ ├── mods │ │ ├── lib.js │ │ ├── package.json │ │ ├── node_modules │ │ │ ├── pkg-lib │ │ │ │ ├── lib.js │ │ │ │ └── package.json │ │ │ └── pkg-esm │ │ │ │ ├── package.json │ │ │ │ └── esm.js │ │ ├── esm.mjs │ │ └── main.js │ ├── callapplymatch.js │ ├── match12.ts │ ├── export3a.mjs │ ├── lib7.mjs │ ├── patterns11.json │ ├── prototypes2.js │ ├── callapplymatch-patterns.json │ ├── externmap-patterns.json │ ├── import11.mjs │ ├── lowpatterns.json │ ├── match1-patterns.json │ ├── match2-patterns.json │ ├── match3-patterns.json │ ├── match4-patterns.json │ ├── match8-patterns.json │ ├── rxjs1.js │ ├── client2.js │ ├── export3c.mjs │ ├── jsx.js │ ├── match6-patterns.json │ ├── match5.js │ ├── match10-patterns.json │ ├── match9-patterns.json │ ├── rest2.js │ ├── match12-patterns.json │ ├── oneshot.js │ ├── prototypes.js │ ├── lib5a.js │ ├── lib5b.js │ ├── match11-patterns.json │ ├── promiseall.js │ ├── default-parameter.js │ ├── import3.mjs │ ├── match8.ts │ ├── match4.js │ ├── client1b.js │ ├── dyn-import.mjs │ ├── lib2.js │ ├── rxjs2.js │ ├── client1.js │ ├── client6.json │ ├── client9.js │ ├── for-in.js │ ├── match3.js │ ├── obj.json │ ├── throw.js │ ├── ts-patterns.json │ ├── regexp.js │ ├── timers.js │ ├── oneshot.json │ ├── arrays4.js │ ├── obj.js │ ├── spawn-cwd.js │ ├── defineProperties.js │ ├── client3.json │ ├── match11.ts │ ├── patterns7.json │ ├── call.json │ ├── rest2.json │ ├── accessors.json │ ├── eval.json │ ├── escape.js │ ├── match7.js │ ├── promiseall.json │ ├── throw.json │ ├── client-this.js │ ├── bind.json │ ├── prototypes2.json │ ├── patterns8.json │ ├── arguments2.js │ ├── templateliterals.js │ ├── client2.json │ ├── for-in.json │ ├── require-extensions.js │ ├── ts.ts │ ├── accessors5.json │ ├── arrays.js │ ├── timers.json │ ├── arrays.json │ ├── require-extensions.json │ ├── accessors6.json │ ├── create.json │ ├── obj2.js │ ├── import12.json │ ├── assign2.json │ ├── classes3.js │ ├── defineProperties.json │ ├── export2.mjs │ ├── match5-patterns.json │ ├── prototypes.json │ ├── match7-patterns.json │ ├── classes3.json │ ├── receiver-callee-mixup.js │ ├── accessors3.json │ ├── client1.json │ ├── eval.js │ ├── default-parameter.json │ ├── spawn-cwd.json │ ├── dyn-import.json │ ├── mix.json │ ├── accessors.js │ ├── create.js │ ├── arrays3.json │ ├── assign1.json │ ├── lib4.js │ ├── match2.js │ ├── accessors6.js │ ├── obj2.json │ ├── arrays3.js │ ├── low.ts │ ├── lib1.js │ ├── rxjs.json │ ├── client4.json │ ├── templateliterals.json │ ├── arrays4.json │ ├── client9.json │ ├── accessors5.js │ ├── client5.json │ ├── match1.js │ ├── match6.js │ ├── super3.json │ ├── dpr-this.js │ ├── arrays2.json │ ├── dpr-this.json │ ├── match10.ts │ ├── prototypes3.json │ ├── assign1.js │ ├── accessors2.js │ ├── promises2.js │ ├── undeclared.js │ ├── promises2.json │ ├── receiver-callee-mixup.json │ ├── arrays5.js │ ├── arrays5.json │ ├── escape-patterns.json │ ├── super2.json │ ├── client-this.json │ ├── mix.js │ ├── client4.js │ ├── import1.json │ ├── super3.js │ ├── match9.ts │ ├── super5.json │ ├── client5.js │ ├── private.json │ ├── this.json │ ├── accessors3.js │ ├── arguments.json │ ├── arrays2.js │ ├── patterns.json │ ├── super5.js │ ├── private.js │ ├── this.js │ ├── prototypes3.js │ ├── defineProperty.json │ ├── accessors4.js │ ├── destructuring.json │ ├── super4.json │ ├── import1.mjs │ ├── assign2.js │ ├── arguments.js │ ├── export1.mjs │ ├── spread.json │ ├── super4.js │ ├── super.json │ ├── call-expressions.js │ ├── super2.js │ ├── fun2.js │ ├── asyncawait.json │ ├── fun.js │ ├── spread.js │ ├── destructuring.js │ ├── fun.json │ ├── rest.json │ ├── more1.json │ ├── call-expressions.json │ ├── generators.json │ ├── iterators.json │ ├── promises.json │ ├── jsx2.jsx │ ├── more1.js │ ├── defineProperty.js │ ├── super.js │ ├── asyncawait.js │ ├── rest.js │ ├── classes.json │ ├── generators.js │ ├── classes2.json │ └── iterators.js ├── approx │ ├── hoist.js │ ├── staticRequire.json │ ├── newNative.json │ ├── library.js │ ├── node_modules │ │ ├── esm │ │ │ ├── lib.mjs │ │ │ └── package.json │ │ └── foolib │ │ │ ├── index.js │ │ │ └── package.json │ ├── function.json │ ├── hints-partialHints.json │ ├── function.js │ ├── newNative.js │ ├── packageStructure │ │ ├── package.json │ │ ├── index.js │ │ └── test │ │ │ └── some.test.js │ ├── hints-hoist.json │ ├── package.json │ ├── dynamic.json │ ├── library.json │ ├── staticRequire.js │ ├── hints-sandbox.json │ ├── hints-stdlib.json │ ├── hints-function.json │ ├── srcLoc.json │ ├── deconstruction.json │ ├── hints-proxy.json │ ├── hints-staticRequire.json │ ├── dynamic.js │ ├── hints-newNative.json │ ├── hints-packageStructure.json │ ├── esm.mjs │ ├── this.json │ ├── computedProperties.json │ ├── hints-srcLoc.json │ ├── hintsOnly │ │ ├── asyncGenerator.js │ │ ├── sandbox.js │ │ ├── proxy.js │ │ ├── stdlib.js │ │ └── forced.js │ ├── natives.json │ ├── hints-library.json │ ├── simple.json │ ├── hints-conditional.json │ ├── srcLoc.js │ ├── hints-asyncGenerator.json │ ├── hints-ts-file.json │ ├── hints-deconstruction.json │ ├── hints-dynamic.json │ ├── hints-this.json │ ├── hints-esm.json │ ├── deconstruction.js │ ├── this.js │ ├── ts-file.ts │ ├── hints-forced.json │ ├── computedProperties.js │ ├── generate-approx.sh │ ├── natives.js │ └── simple.js ├── mochatest │ ├── mylib.js │ ├── require-hook.js │ ├── package.json │ ├── test.json │ ├── test.js │ ├── test-with-hook.json │ └── jelly.test.ts ├── npm-packages │ ├── package.json │ └── jelly.test.ts ├── helloworld │ ├── package.json │ ├── app.js │ └── jelly.test.ts ├── vulnerabilities │ ├── package.json │ └── sample.js ├── install.sh └── regenerate-dynamic-callgraphs.sh ├── .gitignore ├── misc └── winston-cg.png ├── .npmrc ├── .dockerignore ├── .gitattributes ├── tsconfig-build.json ├── .idea ├── codeStyles │ └── codeStyleConfig.xml ├── vcs.xml ├── jsLibraryMappings.xml ├── .gitignore ├── misc.xml ├── modules.xml └── jelly.iml ├── jest.config.js ├── bin ├── jelly-docker └── node ├── src ├── misc │ ├── timer.ts │ ├── memory.ts │ └── worklist.ts ├── testing │ ├── fetch.ts │ └── runner.ts ├── dynamic │ └── sources.ts ├── typings │ ├── vulnerabilities.ts │ ├── callgraph.ts │ └── tapir.ts ├── output │ └── tostringwithcode.ts └── analysis │ ├── modulefinder.ts │ ├── listeners.ts │ └── accesspaths.ts ├── LICENSE └── Dockerfile /tests/micro/node_modules/rxjs/Rx.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/micro/twoversions/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /tests/micro/undecl2.js: -------------------------------------------------------------------------------- 1 | x = () => {} 2 | -------------------------------------------------------------------------------- /tests/micro/lib6.js: -------------------------------------------------------------------------------- 1 | console.log("Hello!"); 2 | -------------------------------------------------------------------------------- /tests/micro/call.js: -------------------------------------------------------------------------------- 1 | 2 | function f() {} 3 | f.call(); 4 | -------------------------------------------------------------------------------- /tests/micro/export10.mjs: -------------------------------------------------------------------------------- 1 | export * from "./lib10.mjs"; 2 | -------------------------------------------------------------------------------- /tests/micro/sub/index.js: -------------------------------------------------------------------------------- 1 | require("../lib3.js").foo(); 2 | -------------------------------------------------------------------------------- /tests/micro/undecl1.js: -------------------------------------------------------------------------------- 1 | require("./undecl2") 2 | 3 | x() 4 | -------------------------------------------------------------------------------- /tests/micro/client6.js: -------------------------------------------------------------------------------- 1 | require("./lib6"); 2 | require("./lib6"); 3 | -------------------------------------------------------------------------------- /tests/micro/packagejson/index.js: -------------------------------------------------------------------------------- 1 | require('terser').minify(); 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | /lib/ 3 | /tmp/ 4 | /dist/ 5 | /.idea/ 6 | -------------------------------------------------------------------------------- /tests/micro/client8.js: -------------------------------------------------------------------------------- 1 | const w = require('winston'); 2 | 3 | w.Logger(); -------------------------------------------------------------------------------- /tests/micro/flow.js: -------------------------------------------------------------------------------- 1 | function maybe(f:?number) { 2 | } 3 | 4 | maybe(1); -------------------------------------------------------------------------------- /tests/micro/import7.mjs: -------------------------------------------------------------------------------- 1 | import w from './lib7.mjs'; 2 | 3 | w.foo(); 4 | -------------------------------------------------------------------------------- /tests/micro/import10.mjs: -------------------------------------------------------------------------------- 1 | import {foo} from "./export10.mjs" 2 | foo(); 3 | -------------------------------------------------------------------------------- /tests/micro/import12.mjs: -------------------------------------------------------------------------------- 1 | import { foo } from "node-exports"; 2 | foo(); 3 | -------------------------------------------------------------------------------- /tests/micro/bind.js: -------------------------------------------------------------------------------- 1 | const f = function(){}.bind({}); 2 | f(); 3 | f.call({}); 4 | -------------------------------------------------------------------------------- /tests/micro/globals/sample/app.js: -------------------------------------------------------------------------------- 1 | require('lib1') 2 | 3 | foo.bar(); 4 | baz(); -------------------------------------------------------------------------------- /tests/micro/lib10.mjs: -------------------------------------------------------------------------------- 1 | export function foo() { 2 | console.log("foo"); 3 | } 4 | -------------------------------------------------------------------------------- /tests/micro/twoversions/index.js: -------------------------------------------------------------------------------- 1 | require('boxen'); 2 | require('ansi-regex')(); 3 | -------------------------------------------------------------------------------- /tests/micro/twoversions/node_modules/boxen/index.js: -------------------------------------------------------------------------------- 1 | require('ansi-regex')(); 2 | -------------------------------------------------------------------------------- /misc/winston-cg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-au-dk/jelly/HEAD/misc/winston-cg.png -------------------------------------------------------------------------------- /tests/micro/import-default/b.d.ts: -------------------------------------------------------------------------------- 1 | declare function f(): void; 2 | 3 | export = f; 4 | -------------------------------------------------------------------------------- /tests/micro/lib3.js: -------------------------------------------------------------------------------- 1 | module.exports.foo = () => { 2 | console.log("hello"); 3 | }; 4 | -------------------------------------------------------------------------------- /tests/micro/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "micro", 3 | "version": "0.0.1" 4 | } 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | scope=@cs-au-dk 2 | access=public 3 | @cs-au-dk:registry=https://registry.npmjs.org/ -------------------------------------------------------------------------------- /tests/approx/hoist.js: -------------------------------------------------------------------------------- 1 | bar["p" + "p"] = function() {} 2 | bar.pp() 3 | function bar() {} 4 | -------------------------------------------------------------------------------- /tests/micro/client3.js: -------------------------------------------------------------------------------- 1 | const lib = require('./lib3'); 2 | 3 | const f = (0, lib.foo)(); 4 | -------------------------------------------------------------------------------- /tests/micro/packagealias/node_modules/set-value/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function() {} 2 | -------------------------------------------------------------------------------- /tests/micro/peerdep/peerdep.js: -------------------------------------------------------------------------------- 1 | module.exports = function(ajv) { 2 | ajv.foo() 3 | } 4 | -------------------------------------------------------------------------------- /tests/micro/import9.mjs: -------------------------------------------------------------------------------- 1 | import c from "./export9.mjs" 2 | 3 | new c(() => {console.log("@")}); -------------------------------------------------------------------------------- /tests/micro/packagealias/index.js: -------------------------------------------------------------------------------- 1 | const merge = require('merge-value-alias'); 2 | merge(); 3 | -------------------------------------------------------------------------------- /tests/micro/date.js: -------------------------------------------------------------------------------- 1 | var d = new Date(); 2 | console.log(d.getDay()); 3 | console.log(Date.now()); 4 | -------------------------------------------------------------------------------- /tests/micro/packagejson/node_modules/terser/dist/index.js: -------------------------------------------------------------------------------- 1 | module.exports.minify = function () {} 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | /tmp 3 | /src 4 | /coverage 5 | /tests 6 | *.md 7 | /.idea 8 | /.git 9 | -------------------------------------------------------------------------------- /tests/micro/export3b.mjs: -------------------------------------------------------------------------------- 1 | let myClass = class { 2 | constructor() { 3 | } 4 | }; 5 | export {myClass}; -------------------------------------------------------------------------------- /tests/micro/export9.mjs: -------------------------------------------------------------------------------- 1 | export default class { 2 | constructor(f) { 3 | f(); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/micro/externmap.js: -------------------------------------------------------------------------------- 1 | const globParent = require('glob-parent'); 2 | ['foo', 'bar'].map(globParent); 3 | -------------------------------------------------------------------------------- /tests/micro/mods/lib.js: -------------------------------------------------------------------------------- 1 | exports.greet = function greet(name) { 2 | return `Hello, ${name}!`; 3 | }; 4 | -------------------------------------------------------------------------------- /tests/micro/mods/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mods", 3 | "private": true, 4 | "version": "1.0.0" 5 | } -------------------------------------------------------------------------------- /tests/micro/twoversions/node_modules/ansi-regex/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function notVulnerable() {}; 2 | -------------------------------------------------------------------------------- /tests/micro/callapplymatch.js: -------------------------------------------------------------------------------- 1 | const n = require('bar'); 2 | n.foo(); 3 | n.foo.call(); 4 | n.foo.apply(); 5 | -------------------------------------------------------------------------------- /tests/micro/globals/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lib1", 3 | "version": "0.1.2", 4 | "main": "./lib1/lib.js"} -------------------------------------------------------------------------------- /tests/micro/match12.ts: -------------------------------------------------------------------------------- 1 | import { editor } from 'monaco-editor'; 2 | import IContentWidget = editor.IContentWidget; -------------------------------------------------------------------------------- /tests/micro/node_modules/node-exports/index.mjs: -------------------------------------------------------------------------------- 1 | export function foo() { 2 | console.log("ESM"); 3 | }; 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | *.{cmd,[cC}[mM][dD]} text eol=crlf 3 | *.{bat,[bB}[aA][tT]} text eol=crlf 4 | -------------------------------------------------------------------------------- /tests/micro/export3a.mjs: -------------------------------------------------------------------------------- 1 | let myFunction = function() {}; 2 | let myVariable = 42; 3 | export {myFunction, myVariable}; -------------------------------------------------------------------------------- /tests/micro/lib7.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | foo: function () { 3 | console.log("hello!"); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/micro/patterns11.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "call ?**.take" 5 | } 6 | ] -------------------------------------------------------------------------------- /tests/micro/prototypes2.js: -------------------------------------------------------------------------------- 1 | let f = () => console.log("f"); 2 | class A {} 3 | A.prototype.t = f; 4 | (new A).t(); 5 | -------------------------------------------------------------------------------- /tests/micro/callapplymatch-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "call .foo" 5 | } 6 | ] 7 | -------------------------------------------------------------------------------- /tests/micro/externmap-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "call " 5 | } 6 | ] 7 | -------------------------------------------------------------------------------- /tests/micro/globals/lib1/lib.js: -------------------------------------------------------------------------------- 1 | global.foo = { 2 | bar: function() {} 3 | } 4 | 5 | globalThis.baz = () => {}; 6 | -------------------------------------------------------------------------------- /tests/micro/import-default/a.ts: -------------------------------------------------------------------------------- 1 | // npx ts-node tests/micro/import-default/a.ts 2 | 3 | import ddd from "./b" 4 | ddd() 5 | -------------------------------------------------------------------------------- /tests/micro/import11.mjs: -------------------------------------------------------------------------------- 1 | import { Subject } from 'rxjs/Subject'; 2 | 3 | Subject().take(1); 4 | new Subject().take(1); 5 | -------------------------------------------------------------------------------- /tests/micro/lowpatterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "read {,}.f.g" 5 | } 6 | ] 7 | -------------------------------------------------------------------------------- /tests/micro/match1-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "read ?**.params" 5 | } 6 | ] -------------------------------------------------------------------------------- /tests/micro/match2-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "read ?**.routes" 5 | } 6 | ] -------------------------------------------------------------------------------- /tests/micro/match3-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "call ?**.save" 5 | } 6 | ] -------------------------------------------------------------------------------- /tests/micro/match4-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "call ?**.mergeMap" 5 | } 6 | ] -------------------------------------------------------------------------------- /tests/micro/match8-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "read ()?.json" 5 | } 6 | ] -------------------------------------------------------------------------------- /tests/micro/mods/node_modules/pkg-lib/lib.js: -------------------------------------------------------------------------------- 1 | exports.greet = function greet(name) { 2 | return `Hello, ${name}!`; 3 | }; -------------------------------------------------------------------------------- /tests/micro/rxjs1.js: -------------------------------------------------------------------------------- 1 | import { default as renderToString } from './rxjs2.js'; 2 | 3 | var x = renderToString().catch(); 4 | -------------------------------------------------------------------------------- /tests/micro/twoversions/node_modules/boxen/node_modules/ansi-regex/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function vulnerable() {}; 2 | -------------------------------------------------------------------------------- /tests/mochatest/mylib.js: -------------------------------------------------------------------------------- 1 | module.exports.plus = (x, y) => x + y; 2 | 3 | module.exports.apply = (f, x, y) => f(x, y); 4 | -------------------------------------------------------------------------------- /tests/micro/client2.js: -------------------------------------------------------------------------------- 1 | const lib = require('./lib2'); 2 | const arit = new lib.Arit(); 3 | 4 | console.log(arit.sum(1, 2)); 5 | -------------------------------------------------------------------------------- /tests/micro/export3c.mjs: -------------------------------------------------------------------------------- 1 | export { myFunction, myVariable } from './export3a.mjs'; 2 | export { myClass } from './export3b.mjs'; -------------------------------------------------------------------------------- /tests/micro/jsx.js: -------------------------------------------------------------------------------- 1 | import {Foo} from "foo"; 2 | var x = {84/2}; 3 | var y = baz ; 4 | -------------------------------------------------------------------------------- /tests/micro/match6-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "call ?**.startWith" 5 | } 6 | ] -------------------------------------------------------------------------------- /tests/micro/node_modules/node-exports/index.js: -------------------------------------------------------------------------------- 1 | module.exports.foo = function() { 2 | console.log("CommonJS"); 3 | }; 4 | -------------------------------------------------------------------------------- /tests/micro/node_modules/rxjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rxjs", 3 | "version": "5.5.12", 4 | "main": "./Rx.js" 5 | } 6 | -------------------------------------------------------------------------------- /tests/micro/packagejson/patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "call .minify" 5 | } 6 | ] 7 | -------------------------------------------------------------------------------- /tests/micro/peerdep/peerdep-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "call ().foo" 5 | } 6 | ] 7 | -------------------------------------------------------------------------------- /tests/npm-packages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm-packages", 3 | "dependencies": { 4 | "glob": "8.0.3" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/micro/import-default/b.js: -------------------------------------------------------------------------------- 1 | module.exports = function() { // using CommonJS default export 2 | console.log(1); 3 | }; 4 | -------------------------------------------------------------------------------- /tests/micro/match5.js: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs/Rx.js' 2 | import { Foo } from 'rxjs' 3 | import { Bar } from 'rxjs/Subject.js' -------------------------------------------------------------------------------- /tests/micro/mods/node_modules/pkg-esm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pkg-esm", 3 | "version": "1.0.0", 4 | "main": "esm.js" 5 | } -------------------------------------------------------------------------------- /tests/micro/mods/node_modules/pkg-lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pkg-lib", 3 | "version": "1.0.0", 4 | "main": "lib.js" 5 | } -------------------------------------------------------------------------------- /tests/micro/match10-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "call ?**.toPromise base:Observable" 5 | } 6 | ] -------------------------------------------------------------------------------- /tests/micro/match9-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "call ?**.toPromise base:Observable" 5 | } 6 | ] -------------------------------------------------------------------------------- /tests/micro/rest2.js: -------------------------------------------------------------------------------- 1 | function f(...args) { 2 | args[0](); 3 | } 4 | function g() { 5 | console.log("here"); 6 | } 7 | f(g); 8 | -------------------------------------------------------------------------------- /tests/micro/match12-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "read .editor.IContentWidget" 5 | } 6 | ] -------------------------------------------------------------------------------- /tests/micro/oneshot.js: -------------------------------------------------------------------------------- 1 | function f1() {} 2 | 3 | var t = ((( /*foo*/ (( ((function () { 4 | return f1; 5 | }))() )) /*bar*/ ))); 6 | -------------------------------------------------------------------------------- /tests/micro/prototypes.js: -------------------------------------------------------------------------------- 1 | function C() {} 2 | 3 | C.prototype = { 4 | foo: function () {} 5 | } 6 | 7 | var v = new C(); 8 | v.foo(); 9 | -------------------------------------------------------------------------------- /tests/micro/lib5a.js: -------------------------------------------------------------------------------- 1 | Object.defineProperty(exports, "__esModule", { 2 | value: true 3 | }); 4 | 5 | exports.default = function foo() {} 6 | -------------------------------------------------------------------------------- /tests/micro/lib5b.js: -------------------------------------------------------------------------------- 1 | Object.defineProperty(exports, "__esModule", { 2 | value: true 3 | }); 4 | 5 | exports.default = function bar() {} 6 | -------------------------------------------------------------------------------- /tests/micro/match11-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "read ?**.fromPromise base:Observable" 5 | } 6 | ] -------------------------------------------------------------------------------- /tests/micro/packagejson/node_modules/terser/dist/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dist", 3 | "version": "1.0.0", 4 | "main": "index.js" 5 | } 6 | -------------------------------------------------------------------------------- /tests/micro/packagejson/node_modules/terser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "terser", 3 | "version": "1.0.0", 4 | "main": "dist/index.js" 5 | } 6 | -------------------------------------------------------------------------------- /tests/micro/promiseall.js: -------------------------------------------------------------------------------- 1 | 2 | function f() { 3 | console.log("f") 4 | } 5 | const r=[f]; 6 | Promise.all(r).then(q => q.forEach(m => m())) 7 | -------------------------------------------------------------------------------- /tests/micro/globals/sample/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "sample": "~0.1.2" 6 | } 7 | } -------------------------------------------------------------------------------- /tests/micro/twoversions/node_modules/ansi-regex/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ansi-regex", 3 | "version": "2.0.0", 4 | "main": "index.js" 5 | } 6 | -------------------------------------------------------------------------------- /tests/helloworld/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "helloworld", 3 | "version": "0.0.1", 4 | "dependencies": { 5 | "express": "^4.17.3" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/micro/default-parameter.js: -------------------------------------------------------------------------------- 1 | 2 | function f(x = function(){ console.log("hello");}){ 3 | x(); 4 | } 5 | 6 | function g(x = f()) { } 7 | g(); 8 | -------------------------------------------------------------------------------- /tests/micro/import3.mjs: -------------------------------------------------------------------------------- 1 | import { myFunction, myVariable, myClass } from './export3c.mjs' 2 | 3 | myFunction(); 4 | console.log(myVariable, new myClass); 5 | -------------------------------------------------------------------------------- /tests/micro/match8.ts: -------------------------------------------------------------------------------- 1 | (async function() { 2 | const { default: fetch } = await import("node-fetch"); 3 | await fetch('someUrl').json(); 4 | }()) 5 | -------------------------------------------------------------------------------- /tests/micro/mods/esm.mjs: -------------------------------------------------------------------------------- 1 | import cjsLib from './lib.js'; 2 | 3 | export function callEsm(name) { 4 | return cjsLib.greet(name) + ' (./esm.mjs)'; 5 | } 6 | -------------------------------------------------------------------------------- /tests/micro/match4.js: -------------------------------------------------------------------------------- 1 | const { Observable } = require('rxjs'); 2 | 3 | Observable.interval(5) 4 | .retryWhen(attempts => 5 | attempts.mergeMap()); 6 | -------------------------------------------------------------------------------- /tests/micro/packagealias/node_modules/merge-value-alias/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "merge-value", 3 | "version": "1.0.0", 4 | "main": "index.js" 5 | } 6 | -------------------------------------------------------------------------------- /tests/micro/client1b.js: -------------------------------------------------------------------------------- 1 | const lib1 = require('lib'); 2 | const filter = lib1.filter; 3 | console.log(filter(x => x % 2 === 0)([1, 2, 3])); 4 | lib1.obj.foo = 87; 5 | -------------------------------------------------------------------------------- /tests/micro/dyn-import.mjs: -------------------------------------------------------------------------------- 1 | const { default: function1, function2 } = await import("./export2.mjs"); 2 | function1(10); 3 | function2(10); 4 | console.log("hi"); 5 | -------------------------------------------------------------------------------- /tests/micro/lib2.js: -------------------------------------------------------------------------------- 1 | function Arit () { } 2 | Arit.prototype.sum = (x, y) => x + y; 3 | Arit.prototype.mul = (x, y) => x * y; 4 | 5 | module.exports.Arit = Arit; 6 | -------------------------------------------------------------------------------- /tests/micro/node_modules/library/index.js: -------------------------------------------------------------------------------- 1 | 2 | const a = [1, 2, 3]; 3 | 4 | exports.array = a; 5 | 6 | exports.callback = function callback(f) { 7 | f(a); 8 | }; 9 | -------------------------------------------------------------------------------- /tests/micro/packagealias/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "packagealias", 3 | "dependencies": { 4 | "merge-value-alias": "npm:merge-value@1.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/micro/rxjs2.js: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs/Observable'; 2 | 3 | export default function renderToString() { 4 | return Observable.defer(); 5 | } 6 | 7 | -------------------------------------------------------------------------------- /tests/micro/client1.js: -------------------------------------------------------------------------------- 1 | const lib1 = require('./lib1.js'); 2 | const filter = lib1.filter; 3 | console.log(filter(x => x % 2 === 0)([1, 2, 3])); 4 | lib1.obj.foo = 87; 5 | -------------------------------------------------------------------------------- /tests/micro/client6.json: -------------------------------------------------------------------------------- 1 | {"entries":["client6.js"],"files":["client6.js","lib6.js"],"functions":["0:1:1:3:1","1:1:1:2:1"],"calls":[],"fun2fun":[],"call2fun":[],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/client9.js: -------------------------------------------------------------------------------- 1 | 2 | const lib = require("library"); 3 | 4 | lib.array.map(i => console.log(i)); 5 | 6 | lib.callback(a => 7 | a.map(i => console.log(i))); 8 | -------------------------------------------------------------------------------- /tests/micro/for-in.js: -------------------------------------------------------------------------------- 1 | const obj = { 2 | a: () => console.log("a"), 3 | b: () => console.log("b"), 4 | }; 5 | 6 | for (const name in obj) 7 | obj[name](); 8 | -------------------------------------------------------------------------------- /tests/micro/match3.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose'; 2 | const schema = mongoose.Schema(); 3 | schema.method('delete', function (cb) { 4 | return this.save(cb); 5 | }) -------------------------------------------------------------------------------- /tests/micro/obj.json: -------------------------------------------------------------------------------- 1 | {"entries":["obj.js"],"files":["obj.js"],"functions":["0:1:1:9:24","0:2:24:4:6"],"calls":["0:9:1:9:23"],"fun2fun":[[0,1]],"call2fun":[[0,1]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/twoversions/node_modules/boxen/node_modules/ansi-regex/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ansi-regex", 3 | "version": "3.0.0", 4 | "main": "index.js" 5 | } 6 | -------------------------------------------------------------------------------- /tests/micro/throw.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function ping() { 4 | throw "pong"; 5 | } 6 | 7 | try { 8 | ping(); 9 | } catch(pong) { 10 | (function(){})(); 11 | } 12 | -------------------------------------------------------------------------------- /tests/micro/ts-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "call .foo 0:Foo 1:string 2:\"bar\" 3:function 4:string 5:42 6:number 7:number" 5 | } 6 | ] -------------------------------------------------------------------------------- /tsconfig-build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src/**/*"], 4 | "files": [], 5 | "compilerOptions": { 6 | "rootDir": "./src", 7 | } 8 | } -------------------------------------------------------------------------------- /tests/micro/mods/node_modules/pkg-esm/esm.js: -------------------------------------------------------------------------------- 1 | import cjsLib from 'pkg-lib'; 2 | 3 | export function callEsm(name) { 4 | return cjsLib.greet(name) + " (pkg-esm/esm.js)"; 5 | } 6 | -------------------------------------------------------------------------------- /tests/micro/regexp.js: -------------------------------------------------------------------------------- 1 | var r1 = RegExp("ab+c"); 2 | r1.test("ab") 3 | 4 | var r2 = /a*b*/; 5 | var a = r2.exec("aaabbb"); 6 | a.find((v) => {console.log("!");return true}); 7 | 8 | -------------------------------------------------------------------------------- /tests/micro/timers.js: -------------------------------------------------------------------------------- 1 | setTimeout((x) => { 2 | x(); 3 | }, 100, () => {console.log("Delayed for 0.1 second.")}); 4 | 5 | queueMicrotask(() => {console.log("Micro task");}); 6 | -------------------------------------------------------------------------------- /tests/vulnerabilities/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tests-vulnerabilities", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "node-etsy-client": "^0.2.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | (cd tests/helloworld; npm ci) 4 | (cd tests/mochatest; npm ci) 5 | (cd tests/vulnerabilities; npm ci) 6 | (cd tests/npm-packages; npm ci) 7 | -------------------------------------------------------------------------------- /tests/micro/oneshot.json: -------------------------------------------------------------------------------- 1 | {"entries":["oneshot.js"],"files":["oneshot.js"],"functions":["0:1:1:6:1","0:3:28:5:2"],"calls":["0:3:28:5:6"],"fun2fun":[[0,1]],"call2fun":[[0,1]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/packagejson/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "packagejson", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "dependencies": { 6 | "terser": "^1.0.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/mochatest/require-hook.js: -------------------------------------------------------------------------------- 1 | require("pirates").addHook( 2 | (code, filename) => filename.endsWith("test.js")? `/* require-hook comment for: ${filename} */\n` + code : code 3 | ); 4 | -------------------------------------------------------------------------------- /tests/micro/arrays4.js: -------------------------------------------------------------------------------- 1 | // exposes bug in native callback handler 2 | function doit(f) { 3 | [() => {}].forEach(f); 4 | f = undefined; 5 | } 6 | 7 | doit(f => f()); 8 | doit(f => f()); 9 | -------------------------------------------------------------------------------- /tests/micro/obj.js: -------------------------------------------------------------------------------- 1 | const person = { 2 | printIntroduction: function() { 3 | console.log("1"); 4 | } 5 | }; 6 | 7 | const me = Object.create(person); 8 | 9 | me.printIntroduction(); -------------------------------------------------------------------------------- /tests/micro/packagealias/node_modules/merge-value-alias/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var set = require('set-value'); 4 | 5 | module.exports = function mergeValue() { 6 | set(); 7 | }; 8 | -------------------------------------------------------------------------------- /tests/micro/spawn-cwd.js: -------------------------------------------------------------------------------- 1 | const { execPath } = require("process"); 2 | const { spawnSync } = require("child_process"); 3 | 4 | spawnSync(execPath, ["index.js"], { 5 | cwd: "sub", 6 | }); 7 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /tests/micro/defineProperties.js: -------------------------------------------------------------------------------- 1 | 2 | const o = {}, descr = { value: function() {} }; 3 | Object.defineProperties(o, { 4 | f: descr, 5 | g: descr, 6 | }); 7 | 8 | o.f(); 9 | o.g(); 10 | -------------------------------------------------------------------------------- /tests/micro/peerdep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "peerdep", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | }, 6 | "peerDependencies": { 7 | "ajv": "^8.12.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/approx/staticRequire.json: -------------------------------------------------------------------------------- 1 | {"entries":["staticRequire.js"],"files":["staticRequire.js"],"functions":["0:1:1:13:2"],"calls":[],"fun2fun":[],"call2fun":[],"ignore":[],"time":"Wed, 10 Jan 2024 12:56:00 GMT"} -------------------------------------------------------------------------------- /tests/micro/client3.json: -------------------------------------------------------------------------------- 1 | {"entries":["client3.js"],"files":["client3.js","lib3.js"],"functions":["0:1:1:4:1","1:1:1:4:1","1:1:22:3:2"],"calls":["0:3:11:3:25"],"fun2fun":[[0,2]],"call2fun":[[0,2]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/match11.ts: -------------------------------------------------------------------------------- 1 | import * as rx from "rxjs"; 2 | 3 | export function from(rx: rx.Observable) { 4 | return rx.fromPromise; 5 | } 6 | 7 | var x = rx.fromPromise; // high confidence match? 8 | -------------------------------------------------------------------------------- /tests/micro/patterns7.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "import " 5 | }, 6 | { 7 | "id": "2", 8 | "pattern": "read .foo" 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /tests/micro/twoversions/node_modules/boxen/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "boxen", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "dependencies": { 6 | "ansi-regex": "^3.0.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/approx/newNative.json: -------------------------------------------------------------------------------- 1 | {"entries":["newNative.js"],"files":["newNative.js"],"functions":["0:1:1:9:39","0:4:20:4:49"],"calls":[],"fun2fun":[],"call2fun":[],"ignore":[],"time":"Tue, 16 Jan 2024 09:44:30 GMT"} -------------------------------------------------------------------------------- /tests/micro/call.json: -------------------------------------------------------------------------------- 1 | {"entries":["call.js"],"files":["call.js"],"functions":["0:1:1:4:1","0:2:1:2:16"],"calls":["0:3:1:3:9"],"fun2fun":[[0,1]],"call2fun":[[0,1]],"ignore":[],"time":"Sun, 06 Aug 2023 20:26:23 GMT"} -------------------------------------------------------------------------------- /tests/micro/rest2.json: -------------------------------------------------------------------------------- 1 | {"entries":["rest2.js"],"files":["rest2.js"],"functions":["0:1:1:8:1","0:1:1:3:2","0:4:1:6:2"],"calls":["0:7:1:7:5","0:2:5:2:14"],"fun2fun":[[0,1],[1,2]],"call2fun":[[0,1],[1,2]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/accessors.json: -------------------------------------------------------------------------------- 1 | {"entries":["accessors.js"],"files":["accessors.js"],"functions":["0:1:1:18:1","0:8:5:10:6","0:5:5:7:6","0:1:1:1:17"],"calls":["0:16:1:16:5"],"fun2fun":[[0,3]],"call2fun":[[0,3]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/eval.json: -------------------------------------------------------------------------------- 1 | {"entries":["eval.js"],"files":["eval.js","lib1.js"],"functions":["0:1:1:13:38","1:1:1:12:1","0:8:1:10:2"],"calls":[],"fun2fun":[],"call2fun":[],"ignore":[],"time":"Fri, 04 Aug 2023 13:08:10 GMT"} -------------------------------------------------------------------------------- /tests/approx/library.js: -------------------------------------------------------------------------------- 1 | var lib = require("foolib"); 2 | 3 | var foo = "foo"; 4 | var bar = "bar"; 5 | 6 | var x = {}; 7 | x[foo] = () => {console.log("!")}; 8 | var t = x[foo]; 9 | t(); 10 | 11 | lib[bar](x); -------------------------------------------------------------------------------- /tests/approx/node_modules/esm/lib.mjs: -------------------------------------------------------------------------------- 1 | export function setProperty(x, y, z) { 2 | x[y] = z 3 | } 4 | 5 | export async function asyncFoo() { 6 | 7 | } 8 | 9 | const x = {} 10 | const p = "pp" 11 | x[p] = {} -------------------------------------------------------------------------------- /tests/micro/escape.js: -------------------------------------------------------------------------------- 1 | const BlueBird = require('bluebird'); 2 | const _ = require('lodash'); 3 | const t = _.template; 4 | BlueBird.promisify(t); 5 | BlueBird.bar = t; 6 | module.exports = t; 7 | module.exports.baz = t; 8 | -------------------------------------------------------------------------------- /tests/micro/match7.js: -------------------------------------------------------------------------------- 1 | var foo = require("foo"); 2 | foo.bar; 3 | foo.a.b.c.bar; 4 | 5 | var baz = require("baz"); 6 | baz.bar; 7 | 8 | var qux = require("qux"); 9 | qux.bar; 10 | 11 | foo.a = qux.q.w.e.r; 12 | -------------------------------------------------------------------------------- /tests/micro/promiseall.json: -------------------------------------------------------------------------------- 1 | {"entries":["promiseall.js"],"files":["promiseall.js"],"functions":["0:1:1:7:1","0:6:21:6:45","0:6:36:6:44","0:2:1:4:2"],"calls":["0:6:41:6:44"],"fun2fun":[[2,3]],"call2fun":[[0,3]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/throw.json: -------------------------------------------------------------------------------- 1 | {"entries":["throw.js"],"files":["throw.js"],"functions":["0:1:1:12:1","0:3:1:5:2","0:10:6:10:18"],"calls":["0:8:5:8:11","0:10:6:10:21"],"fun2fun":[[0,1],[0,2]],"call2fun":[[0,1],[1,2]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/client-this.js: -------------------------------------------------------------------------------- 1 | 2 | const lib = require("library"); 3 | 4 | lib.callback(function() { 5 | this.f = () => console.log("foo"); 6 | }); 7 | 8 | lib.callback(function() { 9 | this.f(); 10 | }); 11 | -------------------------------------------------------------------------------- /tests/approx/function.json: -------------------------------------------------------------------------------- 1 | {"entries":["function.js"],"files":["function.js"],"functions":["0:1:1:10:8","0:7:11:7:25"],"calls":["0:10:1:10:7"],"fun2fun":[[0,1]],"call2fun":[[0,1]],"ignore":[],"time":"Wed, 10 Jan 2024 13:50:29 GMT"} -------------------------------------------------------------------------------- /tests/micro/bind.json: -------------------------------------------------------------------------------- 1 | {"entries":["bind.js"],"files":["bind.js"],"functions":["0:1:1:4:1","0:1:11:1:23"],"calls":["0:2:1:2:4","0:3:1:3:11"],"fun2fun":[[0,1]],"call2fun":[[0,1],[1,1]],"ignore":[],"time":"Tue, 08 Aug 2023 07:50:58 GMT"} -------------------------------------------------------------------------------- /tests/micro/prototypes2.json: -------------------------------------------------------------------------------- 1 | {"entries":["prototypes2.js"],"files":["prototypes2.js"],"functions":["0:1:1:5:1","0:2:1:2:11","0:1:9:1:31"],"calls":["0:4:1:4:12","0:4:1:4:8"],"fun2fun":[[0,1],[0,2]],"call2fun":[[1,1],[0,2]],"ignore":[]} -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/micro/patterns8.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pattern": "read .Logger", 4 | "id": "1", 5 | "changelogDescription": "winston.Logger has been replaced with winston.createLogger.", 6 | "changelogId": "1" 7 | } 8 | ] -------------------------------------------------------------------------------- /tests/approx/hints-partialHints.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:partialHints.js"],"functions":["0:4:1:8:2","0:11:7:11:21","0:15:1:18:2","0:16:12:16:26","0:23:1:26:2","0:30:1:35:2","0:31:17:31:31"],"reads":[],"writes":[],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/micro/arguments2.js: -------------------------------------------------------------------------------- 1 | var x = arguments; 2 | var exp = x[0]; 3 | var req = x[1]; 4 | var mod = x[2]; 5 | 6 | exports.f = () => {}; 7 | require.g = () => {}; 8 | module.h = () => {}; 9 | exp.f(); 10 | req.g(); 11 | mod.h(); 12 | -------------------------------------------------------------------------------- /tests/micro/templateliterals.js: -------------------------------------------------------------------------------- 1 | function fun(strings, p1, p2) { 2 | p1(); 3 | p2(); 4 | return () => {console.log("3")}; 5 | } 6 | const x = fun`foo${ () => {console.log("1")} }bar${ () => {console.log("2")} }baz`; 7 | x(); 8 | -------------------------------------------------------------------------------- /tests/micro/client2.json: -------------------------------------------------------------------------------- 1 | {"entries":["client2.js"],"files":["client2.js","lib2.js"],"functions":["0:1:1:5:1","1:1:1:6:1","1:1:1:1:21","1:2:22:2:37"],"calls":["0:2:14:2:28","0:4:13:4:27"],"fun2fun":[[0,2],[0,3]],"call2fun":[[0,2],[1,3]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/for-in.json: -------------------------------------------------------------------------------- 1 | {"entries":["for-in.js"],"files":["for-in.js"],"functions":["0:1:1:8:1","0:2:8:2:30","0:3:8:3:30"],"calls":["0:7:5:7:16"],"fun2fun":[[0,1],[0,2]],"call2fun":[[0,1],[0,2]],"ignore":[],"time":"Thu, 03 Aug 2023 13:28:04 GMT"} -------------------------------------------------------------------------------- /tests/micro/require-extensions.js: -------------------------------------------------------------------------------- 1 | 2 | const old = require.extensions[".js"]; 3 | require.extensions[".js"] = function (m, filename) { 4 | console.log("Loading " + filename); 5 | old(m, filename); 6 | }; 7 | 8 | require("./lib1.js") 9 | -------------------------------------------------------------------------------- /tests/micro/ts.ts: -------------------------------------------------------------------------------- 1 | import {foo, Foo} from "lib"; 2 | 3 | const a: Foo = new Foo; 4 | const b = "bar"; 5 | const c = () => {}; 6 | const d = "baz" as string; 7 | const e = 42; 8 | const f: number = 117; 9 | foo(a, b, b, c, d, e, e, f); 10 | -------------------------------------------------------------------------------- /tests/mochatest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mochatest", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "test": "mocha" 6 | }, 7 | "devDependencies": { 8 | "mocha": "^9.2.2", 9 | "pirates": "^4.0.6" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/approx/function.js: -------------------------------------------------------------------------------- 1 | const x = new Function('return this;')().Promise 2 | 3 | 4 | const myFunc = new Function('x', 'y', 'z', "x[y] = z"); 5 | const a = {} 6 | const b = 'b' 7 | const c = function () {} 8 | 9 | myFunc(a,b,c) 10 | a[b](); -------------------------------------------------------------------------------- /tests/approx/newNative.js: -------------------------------------------------------------------------------- 1 | const x = {}; 2 | const p = 'p'; 3 | 4 | x[p] = new Promise(function (resolve, reject) {}) 5 | 6 | const map = new Map(); 7 | map['foo'+'bar'] = new Function("return 'baz'"); 8 | 9 | x[map['foo'+'bar']()] = function () {} -------------------------------------------------------------------------------- /tests/micro/accessors5.json: -------------------------------------------------------------------------------- 1 | {"entries":["accessors5.js"],"files":["accessors5.js"],"functions":["0:1:1:16:1","0:7:5:10:6","0:13:11:13:47"],"calls":["0:15:1:15:11"],"fun2fun":[[0,2]],"call2fun":[[0,2]],"ignore":[],"time":"Wed, 06 Dec 2023 10:15:19 GMT"} -------------------------------------------------------------------------------- /tests/micro/arrays.js: -------------------------------------------------------------------------------- 1 | var x = [,() => {}]; 2 | x[42] = () => {}; 3 | x[x] = () => {}; 4 | var y = x[1]; 5 | y(); 6 | var z = x[x]; 7 | z(); 8 | 9 | x.push(() => {}); 10 | var t = x.pop(); 11 | t(); 12 | var t2 = x[3]; 13 | if (t2) t2(); 14 | -------------------------------------------------------------------------------- /tests/micro/timers.json: -------------------------------------------------------------------------------- 1 | {"time":"Sat, 24 Aug 2024 11:36:20 GMT","modules":["micro@0.0.1:timers.js"],"functions":["0","0:5:16:5:50","0:1:12:3:2","0:3:9:3:55"],"entries":["micro@0.0.1:timers.js"],"calls":["0:2:5:2:8"],"fun2fun":[[2,3]],"call2fun":[[0,3]]} -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | 10 | /compiler.xml 11 | -------------------------------------------------------------------------------- /tests/micro/arrays.json: -------------------------------------------------------------------------------- 1 | {"entries":["arrays.js"],"files":["arrays.js"],"functions":["0:1:1:14:1","0:1:11:1:19","0:3:8:3:16","0:9:8:9:16"],"calls":["0:5:1:5:4","0:7:1:7:4","0:11:1:11:4"],"fun2fun":[[0,1],[0,2],[0,3]],"call2fun":[[0,1],[1,2],[2,3]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/require-extensions.json: -------------------------------------------------------------------------------- 1 | {"entries":["require-extensions.js"],"files":["require-extensions.js","lib1.js"],"functions":["0:1:1:9:1","0:3:29:6:2","1:1:1:12:1"],"calls":[],"fun2fun":[],"call2fun":[],"ignore":[],"time":"Mon, 18 Sep 2023 11:44:44 GMT"} -------------------------------------------------------------------------------- /tests/micro/accessors6.json: -------------------------------------------------------------------------------- 1 | {"entries":["accessors6.js"],"files":["accessors6.js"],"functions":["0:1:1:14:1","0:8:29:8:58","0:7:29:7:60","0:1:1:1:17"],"calls":["0:13:1:13:5"],"fun2fun":[[0,3]],"call2fun":[[0,3]],"ignore":[],"time":"Tue, 02 Sep 2025 12:56:01 GMT"} -------------------------------------------------------------------------------- /tests/micro/create.json: -------------------------------------------------------------------------------- 1 | {"entries":["create.js"],"files":["create.js"],"functions":["0:1:1:12:1","0:6:17:6:42","0:2:17:2:42"],"calls":["0:10:1:10:6","0:11:1:11:6"],"fun2fun":[[0,1],[0,2]],"call2fun":[[0,1],[1,2]],"ignore":[],"time":"Wed, 30 Aug 2023 09:36:53 GMT"} -------------------------------------------------------------------------------- /tests/micro/obj2.js: -------------------------------------------------------------------------------- 1 | 2 | function f() {} 3 | function g() {} 4 | 5 | const o1 = {f}; 6 | const o2 = Object(o1); 7 | o2.g = g; 8 | 9 | o1.f(); 10 | o1.g(); 11 | o2.f(); 12 | o2.g(); 13 | 14 | const o3 = Object("hello"); 15 | o3.f = f; 16 | o3.f(); 17 | -------------------------------------------------------------------------------- /tests/micro/import12.json: -------------------------------------------------------------------------------- 1 | {"entries":["import12.mjs"],"files":["import12.mjs","node_modules/node-exports/index.mjs"],"functions":["0:1:1:3:1","1:1:8:3:2"],"calls":["0:2:1:2:6"],"fun2fun":[[0,1]],"call2fun":[[0,1]],"ignore":[],"time":"Tue, 08 Aug 2023 13:52:29 GMT"} -------------------------------------------------------------------------------- /tests/approx/packageStructure/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "packagestructure", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "author": "", 10 | "license": "ISC" 11 | } 12 | -------------------------------------------------------------------------------- /tests/micro/assign2.json: -------------------------------------------------------------------------------- 1 | {"entries":["assign2.js"],"files":["assign2.js"],"functions":["0:1:1:27:1","0:8:5:11:6","0:3:5:6:6","0:17:14:20:10","0:14:5:14:34"],"calls":["0:26:1:26:13"],"fun2fun":[[0,4]],"call2fun":[[0,4]],"ignore":[],"time":"Fri, 03 Nov 2023 12:02:03 GMT"} -------------------------------------------------------------------------------- /tests/micro/classes3.js: -------------------------------------------------------------------------------- 1 | class C { 2 | constructor() { 3 | return () => {console.log("here")} 4 | } 5 | } 6 | 7 | class Parser extends C { 8 | constructor() { 9 | super() 10 | } 11 | } 12 | 13 | var x = new Parser() 14 | x(); 15 | -------------------------------------------------------------------------------- /tests/micro/defineProperties.json: -------------------------------------------------------------------------------- 1 | {"entries":["defineProperties.js"],"files":["defineProperties.js"],"functions":["0:1:1:10:1","0:2:32:2:45"],"calls":["0:8:1:8:6","0:9:1:9:6"],"fun2fun":[[0,1]],"call2fun":[[0,1],[1,1]],"ignore":[],"time":"Fri, 13 Oct 2023 11:11:10 GMT"} -------------------------------------------------------------------------------- /tests/micro/export2.mjs: -------------------------------------------------------------------------------- 1 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export 2 | 3 | export default function function1(x) { 4 | return x * x * x; 5 | } 6 | 7 | export function function2(x) { 8 | return x * x; 9 | } 10 | -------------------------------------------------------------------------------- /tests/micro/match5-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "import rxjs/Rx" 5 | }, 6 | { 7 | "id": "2", 8 | "pattern": "import rxjs" 9 | }, 10 | { 11 | "id": "3", 12 | "pattern": "import rxjs/Subject" 13 | } 14 | ] -------------------------------------------------------------------------------- /tests/micro/prototypes.json: -------------------------------------------------------------------------------- 1 | {"entries":["prototypes.js"],"files":["prototypes.js"],"functions":["0:1:1:9:1","0:1:1:1:16","0:4:10:4:24"],"calls":["0:7:9:7:16","0:8:1:8:8"],"fun2fun":[[0,1],[0,2]],"call2fun":[[0,1],[1,2]],"ignore":[],"time":"Tue, 31 Oct 2023 09:03:50 GMT"} -------------------------------------------------------------------------------- /tests/micro/match7-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "read ?**.bar" 5 | }, 6 | { 7 | "id": "2", 8 | "pattern": "read ?**.bar" 9 | }, 10 | { 11 | "id": "3", 12 | "pattern": "read .bar" 13 | } 14 | ] -------------------------------------------------------------------------------- /tests/approx/node_modules/foolib/index.js: -------------------------------------------------------------------------------- 1 | var foo = "foo"; 2 | var bar = "bar"; 3 | var baz = "baz" 4 | 5 | var y = {}; 6 | y[baz] = () => {console.log("@")}; 7 | var t = y[baz]; 8 | t(); 9 | 10 | 11 | exports[bar] = (a) => { 12 | y[baz](); 13 | a[foo](); 14 | } -------------------------------------------------------------------------------- /tests/micro/classes3.json: -------------------------------------------------------------------------------- 1 | {"entries":["classes3.js"],"files":["classes3.js"],"functions":["0:1:1:15:1","0:7:1:11:2","0:1:1:5:2","0:3:16:3:43"],"calls":["0:13:9:13:21","0:14:1:14:4"],"fun2fun":[[0,1],[0,3]],"call2fun":[[0,1],[1,3]],"ignore":[],"time":"Sun, 07 Jan 2024 12:53:10 GMT"} -------------------------------------------------------------------------------- /tests/micro/receiver-callee-mixup.js: -------------------------------------------------------------------------------- 1 | 2 | const o1 = { 3 | f() { this.g(); }, 4 | g() { console.log("foo"); }, 5 | }; 6 | 7 | const o2 = { 8 | f() { this.g(); }, 9 | g() { console.log("bar"); }, 10 | }; 11 | 12 | (o1 || o2).f(); 13 | (o2 || o1).f(); 14 | -------------------------------------------------------------------------------- /tests/micro/accessors3.json: -------------------------------------------------------------------------------- 1 | {"entries":["accessors3.js"],"files":["accessors3.js"],"functions":["0:1:1:22:1","0:4:5:7:6","0:3:10:3:39","0:10:1:13:2"],"calls":["0:6:9:6:19","0:12:5:12:15"],"fun2fun":[[1,2],[3,2]],"call2fun":[[0,2],[1,2]],"ignore":[],"time":"Thu, 14 Dec 2023 13:06:25 GMT"} -------------------------------------------------------------------------------- /tests/micro/client1.json: -------------------------------------------------------------------------------- 1 | {"entries":["client1.js"],"files":["client1.js","lib1.js"],"functions":["0:1:1:5:1","1:1:1:12:1","1:1:25:10:2","1:2:12:9:6","0:3:20:3:36"],"calls":["0:3:13:3:48","0:3:13:3:37","1:5:17:5:28"],"fun2fun":[[0,2],[0,3],[3,4]],"call2fun":[[1,2],[0,3],[2,4]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/eval.js: -------------------------------------------------------------------------------- 1 | eval("console.log('HELLO')"); 2 | 3 | var x = new Function("console.log('WORLD')"); 4 | x(); 5 | 6 | require("./lib1") 7 | 8 | function foo(x) { 9 | return x + 1; 10 | } 11 | 12 | console.log(eval("foo(2)")) 13 | console.log(eval("(x => x + 1)(10)")) -------------------------------------------------------------------------------- /tests/approx/hints-hoist.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:hoist.js"],"functions":["0:1:18:1:31","0:3:1:3:18"],"reads":[],"writes":[{"type":"normal","loc":"0:1:1:1:31","baseLoc":"0:3:1:3:18","baseType":"Function","prop":"pp","valLoc":"0:1:18:1:31","valType":"Function"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/micro/default-parameter.json: -------------------------------------------------------------------------------- 1 | {"entries":["default-parameter.js"],"files":["default-parameter.js"],"functions":["0:1:1:8:1","0:2:1:4:2","0:2:16:2:50","0:6:1:6:24"],"calls":["0:7:1:7:4","0:6:16:6:19","0:3:5:3:8"],"fun2fun":[[0,1],[0,3],[1,2]],"call2fun":[[1,1],[2,2],[0,3]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/spawn-cwd.json: -------------------------------------------------------------------------------- 1 | {"entries":["spawn-cwd.js","sub/index.js"],"files":["spawn-cwd.js","sub/index.js","lib3.js"],"functions":["0:1:1:7:1","1:1:1:2:1","2:1:1:4:1","2:1:22:3:2"],"calls":["1:1:1:1:28"],"fun2fun":[[1,3]],"call2fun":[[0,3]],"ignore":[],"time":"Thu, 24 Aug 2023 12:17:34 GMT"} -------------------------------------------------------------------------------- /tests/vulnerabilities/sample.js: -------------------------------------------------------------------------------- 1 | var EtsyClient = require('node-etsy-client'); 2 | async function doIt() { 3 | var client = new EtsyClient(); 4 | var shops = await client.findAllShops({'shop_name':'mony', limit:10}); 5 | console.log(shops); 6 | } 7 | if (false) 8 | doIt(); 9 | -------------------------------------------------------------------------------- /tests/approx/node_modules/esm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "esm", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "lib.mjs", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC" 11 | } 12 | -------------------------------------------------------------------------------- /tests/micro/dyn-import.json: -------------------------------------------------------------------------------- 1 | {"entries":["dyn-import.mjs"],"files":["dyn-import.mjs","export2.mjs"],"functions":["0:1:1:5:1","1:1:1:10:1","1:3:16:5:2","1:7:8:9:2"],"calls":["0:2:1:2:14","0:3:1:3:14"],"fun2fun":[[0,2],[0,3]],"call2fun":[[0,2],[1,3]],"ignore":[],"time":"Fri, 15 Sep 2023 08:52:56 GMT"} -------------------------------------------------------------------------------- /tests/micro/mix.json: -------------------------------------------------------------------------------- 1 | {"entries":["mix.js"],"files":["mix.js"],"functions":["0:1:1:19:1","0:4:10:4:39","0:12:8:12:37","0:16:21:16:43"],"calls":["0:6:1:6:4","0:14:1:14:4","0:17:1:17:7"],"fun2fun":[[0,1],[0,2],[0,3]],"call2fun":[[0,1],[1,2],[2,3]],"ignore":[],"time":"Fri, 04 Aug 2023 13:17:12 GMT"} -------------------------------------------------------------------------------- /tests/approx/node_modules/foolib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foolib", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC" 11 | } 12 | -------------------------------------------------------------------------------- /tests/micro/accessors.js: -------------------------------------------------------------------------------- 1 | function f1() {} 2 | 3 | const obj = { 4 | baz: undefined, 5 | get foo() { 6 | return this.baz; 7 | }, 8 | set bar(x) { 9 | this.baz = x; 10 | } 11 | } 12 | 13 | obj.bar = f1; 14 | 15 | const t1 = obj.foo; 16 | t1(); 17 | 18 | -------------------------------------------------------------------------------- /tests/micro/create.js: -------------------------------------------------------------------------------- 1 | const proto1 = Object.create(null, { 2 | g: { value: () => console.log("in g") }, 3 | }); 4 | 5 | const proto2 = Object.create(proto1, { 6 | f: { value: () => console.log("in f") }, 7 | }); 8 | 9 | const o = Object.create(proto2); 10 | o.f(); 11 | o.g(); 12 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/micro/arrays3.json: -------------------------------------------------------------------------------- 1 | {"entries":["arrays3.js"],"files":["arrays3.js"],"functions":["0:1:1:12:1","0:2:2:2:25","0:6:14:6:38","0:11:25:11:49"],"calls":["0:2:1:2:49","0:9:1:9:27","0:11:1:11:52"],"fun2fun":[[0,1],[0,2],[0,3]],"call2fun":[[0,1],[1,2],[2,3]],"ignore":[],"time":"Mon, 11 Sep 2023 08:33:08 GMT"} -------------------------------------------------------------------------------- /tests/micro/assign1.json: -------------------------------------------------------------------------------- 1 | {"entries":["assign1.js"],"files":["assign1.js"],"functions":["0:1:1:19:1","0:3:5:3:35","0:12:5:12:35","0:14:5:14:34"],"calls":["0:8:1:8:9","0:17:1:17:9","0:18:1:18:9"],"fun2fun":[[0,1],[0,2],[0,3]],"call2fun":[[0,1],[1,2],[2,3]],"ignore":[],"time":"Fri, 03 Nov 2023 11:46:36 GMT"} -------------------------------------------------------------------------------- /tests/micro/lib4.js: -------------------------------------------------------------------------------- 1 | Object.defineProperty(exports, "__esModule", { value: true }); 2 | class Timer { 3 | constructor() { 4 | this.startTime = new Date(); 5 | } 6 | elapsed() { 7 | return new Date().getTime() - this.startTime.getTime(); 8 | } 9 | } 10 | exports.default = Timer; 11 | -------------------------------------------------------------------------------- /tests/micro/match2.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const serverObject = { }; 3 | function addServer(serverName) { 4 | const app = express(); 5 | serverObject[serverName] = { 6 | app: app, 7 | }; 8 | } 9 | addServer('server1') 10 | serverObject.server1.app.routes.get -------------------------------------------------------------------------------- /tests/micro/accessors6.js: -------------------------------------------------------------------------------- 1 | function f1() {} 2 | 3 | const obj = { 4 | baz: undefined, 5 | } 6 | 7 | obj.__defineGetter__('foo', function() { return this.baz; }); 8 | obj.__defineSetter__('bar', function(x) { this.baz = x; }); 9 | 10 | obj.bar = f1; 11 | 12 | const t1 = obj.foo; 13 | t1(); 14 | -------------------------------------------------------------------------------- /tests/micro/obj2.json: -------------------------------------------------------------------------------- 1 | {"entries":["obj2.js"],"files":["obj2.js"],"functions":["0:1:1:17:1","0:2:1:2:16","0:3:1:3:16"],"calls":["0:9:1:9:7","0:10:1:10:7","0:11:1:11:7","0:12:1:12:7","0:16:1:16:7"],"fun2fun":[[0,1],[0,2]],"call2fun":[[0,1],[1,2],[2,1],[3,2],[4,1]],"ignore":[],"time":"Thu, 31 Aug 2023 13:41:00 GMT"} -------------------------------------------------------------------------------- /tests/micro/arrays3.js: -------------------------------------------------------------------------------- 1 | 2 | [() => console.log("hi")].reduce(() => void 0)(); 3 | 4 | const arr = [123]; 5 | for (let i = 0; i < 10; i++) 6 | arr[i] = () => console.log("hi2"); 7 | 8 | arr.length = 1; 9 | arr.reduce(() => void 0)(); 10 | 11 | [].reduce(() => void 0, () => console.log("hi3"))(); 12 | -------------------------------------------------------------------------------- /tests/micro/low.ts: -------------------------------------------------------------------------------- 1 | var x1; 2 | x1 = require("foo"); 3 | x1 = require("bar"); 4 | x1 = {} 5 | var y1 = x1.f.g; 6 | 7 | var x2; 8 | x2 = require("foo"); 9 | x2 = require("bar"); 10 | var y2 = x2.f.g; 11 | 12 | var x3; 13 | x3 = require("foo"); 14 | x3.f = require("bar").f; 15 | var y3 = x3.f.g; 16 | 17 | -------------------------------------------------------------------------------- /tests/micro/lib1.js: -------------------------------------------------------------------------------- 1 | module.exports.filter = (iteratee) => { 2 | return (arr) => { 3 | const res = []; 4 | for (var x of arr) { 5 | if (iteratee(x)) 6 | res.push(x); 7 | } 8 | return res; 9 | }; 10 | } 11 | module.exports.obj = {foo: 17}; 12 | -------------------------------------------------------------------------------- /tests/micro/rxjs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pattern": "read ?**.{do,catch,switch,finally}", 4 | "id": "103a", 5 | "changelogDescription": "Operator renames: do -> tap, catch -> catchError, switch -> switchAll, finally -> finalize, throw -> throwError\n", 6 | "changelogId": "23" 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: "ts-jest", 3 | testEnvironment: "node", 4 | maxWorkers: 1, 5 | setupFilesAfterEnv: ["jest-expect-message"], 6 | coverageProvider: "v8", 7 | coverageDirectory: "tmp/coverage", 8 | roots: ["tests"], 9 | testMatch: ["**/*.test.ts"] 10 | }; 11 | -------------------------------------------------------------------------------- /tests/micro/client4.json: -------------------------------------------------------------------------------- 1 | {"entries":["client4.js"],"files":["client4.js","lib4.js","lib3.js"],"functions":["0:1:1:10:1","1:1:1:11:1","0:1:57:3:2","2:1:1:4:1","1:2:1:9:2","1:6:3:8:4"],"calls":["0:4:17:4:51","0:5:14:5:48","0:7:15:7:36","0:9:37:9:52"],"fun2fun":[[0,2],[0,4],[0,5]],"call2fun":[[0,2],[1,2],[2,4],[3,5]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/node_modules/library/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "library", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC" 12 | } 13 | -------------------------------------------------------------------------------- /tests/micro/templateliterals.json: -------------------------------------------------------------------------------- 1 | {"entries":["templateliterals.js"],"files":["templateliterals.js"],"functions":["0:1:1:8:1","0:1:1:5:2","0:6:21:6:45","0:6:53:6:77","0:4:12:4:36"],"calls":["0:6:11:6:82","0:2:5:2:9","0:3:5:3:9","0:7:1:7:4"],"fun2fun":[[0,1],[0,4],[1,2],[1,3]],"call2fun":[[0,1],[1,2],[2,3],[3,4]],"ignore":[]} -------------------------------------------------------------------------------- /tests/mochatest/test.json: -------------------------------------------------------------------------------- 1 | {"entries":["node_modules/.bin/mocha"],"files":["test.js","mylib.js"],"functions":["0:1:1:12:1","1:1:1:4:1","0:4:19:11:2","0:5:39:7:6","1:1:23:1:38","0:8:30:10:6","1:3:24:3:44"],"calls":["0:6:26:6:42","0:9:19:9:48","1:3:37:3:44"],"fun2fun":[[3,4],[5,6],[6,4]],"call2fun":[[0,4],[1,6],[2,4]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/arrays4.json: -------------------------------------------------------------------------------- 1 | {"entries":["arrays4.js"],"files":["arrays4.js"],"functions":["0:1:1:9:1","0:2:1:5:2","0:7:6:7:14","0:3:6:3:14","0:8:6:8:14"],"calls":["0:7:1:7:15","0:7:11:7:14","0:8:1:8:15","0:8:11:8:14"],"fun2fun":[[0,1],[2,3],[4,3]],"call2fun":[[0,1],[1,3],[2,1],[3,3]],"ignore":[],"time":"Tue, 17 Oct 2023 14:23:55 GMT"} -------------------------------------------------------------------------------- /tests/micro/client9.json: -------------------------------------------------------------------------------- 1 | {"entries":["client9.js"],"files":["client9.js","node_modules/library/index.js"],"functions":["0:1:1:8:1","1:1:1:9:1","0:4:15:4:34","1:6:20:8:2","0:6:14:7:31","0:7:11:7:30"],"calls":["0:6:1:7:32","1:7:2:7:6"],"fun2fun":[[0,3],[3,4]],"call2fun":[[0,3],[1,4]],"ignore":[],"time":"Tue, 26 Sep 2023 18:30:09 GMT"} -------------------------------------------------------------------------------- /tests/micro/accessors5.js: -------------------------------------------------------------------------------- 1 | 2 | // setter inherited from prototype 3 | 4 | const obj = {}; 5 | 6 | Object.setPrototypeOf(obj, { 7 | set foo(v) { 8 | console.log("setter called"); 9 | this._foo = v; 10 | } 11 | }); 12 | 13 | obj.foo = () => { console.log("foo called"); }; 14 | 15 | obj._foo(); 16 | -------------------------------------------------------------------------------- /tests/micro/client5.json: -------------------------------------------------------------------------------- 1 | {"entries":["client5.js"],"files":["client5.js","lib5a.js","lib5b.js"],"functions":["0:1:1:13:1","1:1:1:6:1","0:1:57:3:2","2:1:1:6:1","1:5:19:5:36","2:5:19:5:36"],"calls":["0:6:15:6:50","0:7:15:7:50","0:10:1:10:16","0:11:1:11:16"],"fun2fun":[[0,2],[0,4],[0,5]],"call2fun":[[0,2],[1,2],[2,4],[3,5]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/match1.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | function BitterServer(opts) { 3 | this.app = express(); 4 | this.app.get(/^\/(\d{4})\/(\d{2})\/(\d+)(-\d+)?\/(.*)$/, (function(_this) { 5 | return function(req) { 6 | req.params[0]; 7 | }})(this)); 8 | } 9 | new BitterServer() 10 | -------------------------------------------------------------------------------- /tests/micro/import-default/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "a.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "types": "./b.d.ts" 13 | } 14 | -------------------------------------------------------------------------------- /tests/micro/match6.js: -------------------------------------------------------------------------------- 1 | import { EmptyObservable } from 'rxjs/observable/EmptyObservable' 2 | 3 | const wrappedEpic = {}; 4 | const $$getObservable = 'foo'; 5 | let lifecycle2 = EmptyObservable.create(); 6 | wrappedEpic[$$getObservable] = () => lifecycle2; 7 | 8 | const lifecycle = wrappedEpic[$$getObservable](); 9 | lifecycle.startWith(null); -------------------------------------------------------------------------------- /tests/micro/packagealias/node_modules/set-value/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "set-value", 3 | "version": "1.0.0", 4 | "description": "", 5 | "license": "ISC", 6 | "author": "", 7 | "type": "commonjs", 8 | "main": "index.js", 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/micro/super3.json: -------------------------------------------------------------------------------- 1 | {"entries":["super3.js"],"files":["super3.js"],"functions":["0:1:1:22:1","0:1:1:20:2","0:10:9:12:10","0:4:9:7:10","0:13:9:15:10"],"calls":["0:21:1:21:6","0:18:5:18:12","0:11:13:11:23","0:6:13:6:22"],"fun2fun":[[0,1],[1,2],[2,3],[3,4]],"call2fun":[[0,1],[1,2],[2,3],[3,4]],"ignore":[],"time":"Tue, 09 Jul 2024 11:29:44 GMT"} -------------------------------------------------------------------------------- /tests/micro/dpr-this.js: -------------------------------------------------------------------------------- 1 | 2 | function Foo() { } 3 | 4 | Foo.prototype.add = function(key, value) { 5 | this[key] = value; 6 | }; 7 | 8 | Foo.prototype.get = function(key) { 9 | return this[key]; 10 | }; 11 | 12 | var foo = new Foo(); 13 | foo.add("bar", () => console.log("bar")); 14 | 15 | const f = foo.get("bar"); 16 | f(); 17 | -------------------------------------------------------------------------------- /tests/approx/packageStructure/index.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | exports = module.exports = {} 4 | 5 | exports.Foo = function (x, y, z) { 6 | foo(x, y, z) 7 | return x; 8 | } 9 | 10 | function foo(x, y, z) { 11 | x[y] = z 12 | if (typeof z === "function") 13 | x[y](); 14 | } 15 | })() -------------------------------------------------------------------------------- /tests/micro/arrays2.json: -------------------------------------------------------------------------------- 1 | {"entries":["arrays2.js"],"files":["arrays2.js"],"functions":["0:1:1:20:5","0:12:15:17:6","0:2:5:2:29","0:5:8:5:32","0:18:9:18:38","0:3:5:3:29","0:16:16:16:40"],"calls":["0:13:9:13:18","0:14:9:14:19","0:15:9:15:17","0:20:1:20:4"],"fun2fun":[[0,6],[1,2],[1,3],[1,4],[1,5]],"call2fun":[[0,2],[0,5],[0,3],[1,3],[2,4],[3,6]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/dpr-this.json: -------------------------------------------------------------------------------- 1 | {"entries":["dpr-this.js"],"files":["dpr-this.js"],"functions":["0:1:1:17:1","0:2:1:2:19","0:4:21:6:2","0:8:21:10:2","0:13:16:13:40"],"calls":["0:12:11:12:20","0:13:1:13:41","0:15:11:15:25","0:16:1:16:4"],"fun2fun":[[0,1],[0,2],[0,3],[0,4]],"call2fun":[[0,1],[1,2],[2,3],[3,4]],"ignore":[],"time":"Thu, 04 Jan 2024 12:21:32 GMT"} -------------------------------------------------------------------------------- /tests/micro/match10.ts: -------------------------------------------------------------------------------- 1 | import * as rx from "rxjs"; 2 | 3 | // if not export, then no argument values and therefore no matches are reported 4 | // uncertain type match because rx.Observable isn't handled by convertType 5 | export async function logObservable(rx: rx.Observable, unitMs: number): Promise { 6 | return rx.toPromise(); 7 | } -------------------------------------------------------------------------------- /tests/micro/prototypes3.json: -------------------------------------------------------------------------------- 1 | {"entries":["prototypes3.js"],"files":["prototypes3.js"],"functions":["0:1:1:32:1","0:2:1:2:18","0:5:5:7:6","0:15:5:17:6","0:24:12:26:6"],"calls":["0:10:11:10:20","0:12:1:12:8","0:20:1:20:8","0:31:1:31:8"],"fun2fun":[[0,1],[0,2],[0,3],[0,4]],"call2fun":[[0,1],[1,2],[2,3],[3,4]],"ignore":[],"time":"Tue, 31 Oct 2023 09:17:48 GMT"} -------------------------------------------------------------------------------- /tests/helloworld/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const app = express(); 4 | 5 | app.get('/', function(req, res) { 6 | res.send("Hello world!"); 7 | console.log("Response sent"); 8 | server.close(); 9 | }); 10 | 11 | const PORT = 3000; 12 | const server = app.listen(PORT); 13 | console.log(`Listening on port ${PORT}`); 14 | -------------------------------------------------------------------------------- /tests/micro/assign1.js: -------------------------------------------------------------------------------- 1 | 2 | const o1 = Object.assign({}, { 3 | foo() { console.log("foo1"); }, 4 | }, { 5 | bar: undefined, 6 | }); 7 | 8 | o1.foo(); 9 | o1.bar?.(); 10 | 11 | const o2 = Object.assign({}, { 12 | foo() { console.log("foo2"); }, 13 | }, { 14 | bar() { console.log("bar"); }, 15 | }); 16 | 17 | o2.foo(); 18 | o2.bar(); 19 | -------------------------------------------------------------------------------- /tests/micro/accessors2.js: -------------------------------------------------------------------------------- 1 | const obj = { 2 | baz: function() { 3 | console.log("hello") 4 | }, 5 | get foo() { 6 | this.baz(); 7 | }, 8 | 9 | set s(x) { 10 | this.bar = x; 11 | } 12 | } 13 | 14 | obj.foo; 15 | 16 | obj.s = function() { 17 | console.log("olleh") 18 | } 19 | obj.bar(); 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/micro/promises2.js: -------------------------------------------------------------------------------- 1 | 2 | (async () => { 3 | function resolveWithFun(resolve) { 4 | resolve(() => console.log("Hello World!")); 5 | } 6 | 7 | const f1 = await new Promise((resolve) => resolveWithFun(resolve)); 8 | f1(); 9 | 10 | const f2 = await new Promise((resolve) => resolveWithFun(resolve)); 11 | f2(); 12 | })(); 13 | -------------------------------------------------------------------------------- /tests/micro/undeclared.js: -------------------------------------------------------------------------------- 1 | a = () => {}; // declared automatically in the global scope 2 | var b = a; 3 | b(); 4 | global.a(); // global is a property of globalThis which is the global scope 5 | globalThis.global.globalThis.a(); 6 | 7 | global.setTimeout(function() {}) 8 | setTimeout(function() {}) 9 | 10 | undefined = () => {}; // non-writable 11 | undefined(); -------------------------------------------------------------------------------- /tests/micro/promises2.json: -------------------------------------------------------------------------------- 1 | {"entries":["promises2.js"],"files":["promises2.js"],"functions":["0:1:1:13:1","0:2:2:12:2","0:7:34:7:70","0:3:5:5:6","0:4:17:4:50","0:10:34:10:70"],"calls":["0:2:1:12:5","0:7:47:7:70","0:8:5:8:9","0:10:47:10:70","0:11:5:11:9"],"fun2fun":[[0,1],[1,4],[2,3],[5,3]],"call2fun":[[0,1],[1,3],[2,4],[3,3],[4,4]],"ignore":[],"time":"Tue, 30 Jan 2024 10:47:03 GMT"} -------------------------------------------------------------------------------- /tests/micro/receiver-callee-mixup.json: -------------------------------------------------------------------------------- 1 | {"entries":["receiver-callee-mixup.js"],"files":["receiver-callee-mixup.js"],"functions":["0:1:1:14:1","0:3:5:3:22","0:4:5:4:32","0:8:5:8:22","0:9:5:9:32"],"calls":["0:12:1:12:15","0:3:11:3:19","0:13:1:13:15","0:8:11:8:19"],"fun2fun":[[0,1],[0,3],[1,2],[3,4]],"call2fun":[[0,1],[1,2],[2,3],[3,4]],"ignore":[],"time":"Thu, 18 Jan 2024 15:23:22 GMT"} -------------------------------------------------------------------------------- /tests/approx/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "approx", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "computedProperties.js", 6 | "dependencies": { 7 | "foolib": "^1.0.0" 8 | }, 9 | "devDependencies": {}, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "", 14 | "license": "ISC" 15 | } 16 | -------------------------------------------------------------------------------- /tests/micro/arrays5.js: -------------------------------------------------------------------------------- 1 | // exposes bug in native callback handler 2 | function doit(callSort, cb) { 3 | const weirdArray = [() => {}, () => {}]; 4 | if (callSort) 5 | weirdArray.forEach = weirdArray.sort; 6 | weirdArray.forEach(cb); 7 | cb = undefined; 8 | } 9 | 10 | doit(false, f => f()); 11 | doit(true, (a, b) => { 12 | a(); 13 | b(); 14 | }); 15 | -------------------------------------------------------------------------------- /tests/approx/dynamic.json: -------------------------------------------------------------------------------- 1 | {"entries":["dynamic.js"],"files":["dynamic.js","node_modules/foolib/index.js"],"functions":["0:1:1:27:14","0:4:12:4:47","0:13:10:13:45","0:21:12:21:47","1:1:1:14:2","1:6:10:6:34"],"calls":["0:10:1:10:7","0:15:1:15:10","0:23:1:23:8","1:8:1:8:4"],"fun2fun":[[0,1],[0,2],[0,3],[4,5]],"call2fun":[[0,1],[1,2],[2,3],[3,5]],"ignore":[],"time":"Wed, 10 Jan 2024 12:55:25 GMT"} -------------------------------------------------------------------------------- /tests/micro/arrays5.json: -------------------------------------------------------------------------------- 1 | {"entries":["arrays5.js"],"files":["arrays5.js"],"functions":["0:1:1:15:1","0:2:1:8:2","0:10:13:10:21","0:3:25:3:33","0:3:35:3:43","0:11:12:14:2"],"calls":["0:10:1:10:22","0:10:18:10:21","0:11:1:14:3","0:12:5:12:8","0:13:5:13:8"],"fun2fun":[[0,1],[2,3],[2,4],[5,4],[5,3]],"call2fun":[[0,1],[1,3],[1,4],[2,1],[3,4],[4,3]],"ignore":[],"time":"Tue, 17 Oct 2023 14:23:44 GMT"} -------------------------------------------------------------------------------- /tests/micro/escape-patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "call .template" 5 | }, 6 | { 7 | "id": "2", 8 | "pattern": "call .template.foo" 9 | }, 10 | { 11 | "id": "3", 12 | "pattern": "write .template.bar" 13 | }, 14 | { 15 | "id": "4", 16 | "pattern": "read .template.baz" 17 | } 18 | ] 19 | -------------------------------------------------------------------------------- /tests/micro/super2.json: -------------------------------------------------------------------------------- 1 | {"entries":["super2.js"],"files":["super2.js"],"functions":["0:1:1:30:1","0:12:1:24:2","0:1:1:10:2","0:13:5:18:6","0:2:5:5:6","0:19:12:23:6","0:6:12:9:6"],"calls":["0:26:9:26:16","0:27:1:27:6","0:14:9:14:18","0:28:1:28:6","0:20:9:20:18"],"fun2fun":[[0,1],[0,3],[0,5],[3,4],[5,6]],"call2fun":[[0,1],[1,3],[2,4],[3,5],[4,6]],"ignore":[],"time":"Sun, 15 Sep 2024 16:16:23 GMT"} -------------------------------------------------------------------------------- /tests/micro/client-this.json: -------------------------------------------------------------------------------- 1 | {"entries":["client-this.js"],"files":["client-this.js","node_modules/library/index.js"],"functions":["0:1:1:11:1","1:1:1:9:1","1:6:20:8:2","0:4:14:6:2","0:8:14:10:2","0:5:14:5:38"],"calls":["0:4:1:6:3","1:7:2:7:6","0:8:1:10:3","0:9:5:9:13"],"fun2fun":[[0,2],[2,3],[2,4],[4,5]],"call2fun":[[0,2],[1,3],[1,4],[2,2],[3,5]],"ignore":[],"time":"Wed, 03 Jan 2024 13:37:28 GMT"} -------------------------------------------------------------------------------- /tests/micro/mix.js: -------------------------------------------------------------------------------- 1 | eval("console.log(42)"); 2 | 3 | var x = new Map(); 4 | x.set(1, function() {console.log("1")}); 5 | var y = x.get(1); 6 | y(); 7 | 8 | var z = new Function("console.log(87)"); 9 | z(); 10 | 11 | var a = new Array(); 12 | a.push(function() {console.log("2")}); 13 | var b = a.pop(); 14 | b() 15 | 16 | var c = Array.from([() => {console.log(3)}]); 17 | c[0](); 18 | 19 | -------------------------------------------------------------------------------- /tests/mochatest/test.js: -------------------------------------------------------------------------------- 1 | var mylib = require('./mylib'); 2 | var assert = require('assert'); 3 | 4 | describe("mylib", function() { 5 | it('plus should return a number', function() { 6 | assert.ok(typeof mylib.plus(4, 2) === 'number'); 7 | }); 8 | it('apply should apply', function() { 9 | assert.ok(mylib.apply(mylib.plus, 4, 2) === 6); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /tests/approx/library.json: -------------------------------------------------------------------------------- 1 | {"entries":["library.js"],"files":["node_modules/foolib/index.js","library.js"],"functions":["1:1:1:11:13","0:1:1:14:2","0:6:10:6:34","1:7:10:7:34","0:11:16:14:2"],"calls":["0:8:1:8:4","1:9:1:9:4","1:11:1:11:12","0:12:5:12:13","0:13:5:13:13"],"fun2fun":[[0,3],[0,4],[1,2],[4,2],[4,3]],"call2fun":[[0,2],[1,3],[2,4],[3,2],[4,3]],"ignore":[],"time":"Wed, 10 Jan 2024 12:55:33 GMT"} -------------------------------------------------------------------------------- /tests/micro/client4.js: -------------------------------------------------------------------------------- 1 | var __importDefault = (this && this.__importDefault) || function (mod) { 2 | return (mod && mod.__esModule) ? mod : { "default": mod }; 3 | }; 4 | const timer_1 = __importDefault(require("./lib4")); 5 | const lib3 = __importDefault(require("./lib3")); 6 | 7 | const timer = new timer_1.default(); 8 | 9 | console.log(`Total analysis time: ${timer.elapsed()}ms`); 10 | -------------------------------------------------------------------------------- /tests/micro/import1.json: -------------------------------------------------------------------------------- 1 | {"entries":["import1.mjs"],"files":["import1.mjs","export2.mjs","export1.mjs"],"functions":["1:1:1:10:1","2:1:1:27:1","0:1:1:23:1","2:17:11:19:6","2:6:1:8:2","2:24:16:26:2","1:3:16:5:2","1:7:8:9:2"],"calls":["0:10:1:10:13","0:11:13:11:20","0:14:13:14:21","0:16:13:16:25","0:17:13:17:25"],"fun2fun":[[2,3],[2,4],[2,5],[2,6],[2,7]],"call2fun":[[0,3],[1,4],[2,5],[3,6],[4,7]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/node_modules/node-exports/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exports", 3 | "version": "1.0.0", 4 | "description": "", 5 | "exports": { 6 | ".": { 7 | "require": "./index.js", 8 | "import": "./index.mjs" 9 | } 10 | }, 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "author": "", 15 | "license": "ISC" 16 | } 17 | -------------------------------------------------------------------------------- /.idea/jelly.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/micro/super3.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | 3 | var q1 = { 4 | m1() { 5 | console.log("q1.m1"); 6 | this.m3(); 7 | } 8 | } 9 | var q2 = { 10 | m2() { 11 | super.m1(); 12 | }, 13 | m3() { 14 | console.log("q2.m3"); 15 | } 16 | } 17 | Object.setPrototypeOf(q2, q1); 18 | q2.m2(); 19 | 20 | } 21 | foo(); 22 | -------------------------------------------------------------------------------- /tests/micro/match9.ts: -------------------------------------------------------------------------------- 1 | import Subject from "rxjs"; 2 | class RestrictionMosaicHttp { 3 | search() { 4 | return new Subject() 5 | } 6 | } 7 | 8 | function assign(object: T): T { 9 | return Object.assign({ __proto__: Object.getPrototypeOf(object) }, object); 10 | } 11 | 12 | const restrictionMosaicRepository = assign(new RestrictionMosaicHttp("someURL")); 13 | restrictionMosaicRepository.search().toPromise(); -------------------------------------------------------------------------------- /tests/micro/super5.json: -------------------------------------------------------------------------------- 1 | {"entries":["super5.js"],"files":["super5.js"],"functions":["0:1:1:25:1","0:10:1:19:2","0:11:12:18:6","0:1:1:8:2","0:14:14:16:14","0:5:5:7:6","0:3:20:3:46","0:6:20:6:46"],"calls":["0:21:9:21:12","0:22:9:22:16","0:14:14:16:17","0:15:17:15:26","0:23:1:23:8","0:24:1:24:8"],"fun2fun":[[0,1],[0,2],[0,6],[0,7],[2,4],[4,5]],"call2fun":[[0,1],[1,2],[2,4],[3,5],[4,6],[5,7]],"ignore":[],"time":"Sun, 22 Sep 2024 15:45:02 GMT"} -------------------------------------------------------------------------------- /tests/micro/client5.js: -------------------------------------------------------------------------------- 1 | var __importDefault = (this && this.__importDefault) || function (mod) { 2 | return (mod && mod.__esModule) ? mod : { "default": mod }; 3 | }; 4 | Object.defineProperty(exports, "__esModule", { value: true }); 5 | 6 | const lib5a = __importDefault(require('./lib5a')); 7 | const lib5b = __importDefault(require('./lib5b')); 8 | 9 | console.log(lib5a.default); 10 | lib5a.default(); 11 | lib5b.default(); 12 | 13 | -------------------------------------------------------------------------------- /tests/micro/private.json: -------------------------------------------------------------------------------- 1 | {"entries":["private.js"],"files":["private.js"],"functions":["0:1:1:25:1","0:8:12:8:46","0:2:5:2:39","0:1:1:22:2","0:2:12:2:38","0:16:21:16:48","0:4:5:6:6","0:8:19:8:45","0:10:12:12:6"],"calls":["0:24:1:24:8","0:15:9:15:20","0:17:9:17:20","0:18:9:18:20","0:19:9:19:17","0:20:9:20:17"],"fun2fun":[[0,3],[3,4],[3,5],[3,6],[3,7],[3,8]],"call2fun":[[0,3],[1,4],[2,5],[3,6],[4,7],[5,8]],"ignore":[],"time":"Sun, 22 Oct 2023 07:35:09 GMT"} -------------------------------------------------------------------------------- /tests/micro/this.json: -------------------------------------------------------------------------------- 1 | {"entries":["this.js"],"files":["this.js"],"functions":["0:1:1:31:1","0:2:8:4:6","0:5:8:7:6","0:16:7:18:2","0:13:7:15:2","0:22:5:24:6","0:23:16:23:32","0:25:5:27:6"],"calls":["0:9:9:9:14","0:10:1:10:4","0:19:1:19:6","0:17:5:17:13","0:29:11:29:18","0:30:1:30:4","0:23:22:23:32"],"fun2fun":[[0,1],[0,2],[0,3],[0,5],[0,6],[3,4],[6,7]],"call2fun":[[0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,7]],"ignore":[],"time":"Wed, 24 Jan 2024 15:02:23 GMT"} -------------------------------------------------------------------------------- /tests/micro/accessors3.js: -------------------------------------------------------------------------------- 1 | 2 | const obj = { 3 | baz: () => { console.log("baz"); }, 4 | set foo(v) { 5 | console.log("foo"); 6 | this.baz(); 7 | }, 8 | }; 9 | 10 | function getter() { 11 | console.log("getter"); 12 | this.baz(); 13 | } 14 | 15 | obj.foo = 123; 16 | 17 | Object.defineProperty(obj, "foo", {set: getter}); 18 | 19 | Object.defineProperty(obj, "bar", {get: getter}); 20 | 21 | const x = obj.bar; 22 | -------------------------------------------------------------------------------- /tests/micro/arguments.json: -------------------------------------------------------------------------------- 1 | {"entries":["arguments.js"],"files":["arguments.js"],"functions":["0:1:1:19:1","0:2:1:11:2","0:12:4:12:28","0:12:30:12:54","0:8:20:8:44","0:14:1:17:2","0:15:15:15:33","0:18:4:18:28"],"calls":["0:12:1:12:55","0:6:5:6:19","0:7:5:7:19","0:9:5:9:8","0:10:5:10:23","0:18:1:18:29","0:16:5:16:10","0:16:5:16:8"],"fun2fun":[[0,1],[0,5],[1,2],[1,3],[1,4],[1,1],[5,6],[5,7]],"call2fun":[[0,1],[1,2],[2,3],[3,4],[4,1],[5,5],[7,6],[6,7]],"ignore":[]} -------------------------------------------------------------------------------- /bin/jelly-docker: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | if [[ -z "$1" ]]; then 3 | echo "Error: Workspace root directory missing, aborting" 4 | exit 255 5 | fi 6 | 7 | if docker info --format '{{join .SecurityOptions "\n"}}' | grep --silent "name=rootless"; then 8 | OPTS="" 9 | else 10 | OPTS="--user $(id -u):$(id -g) -e HOME=/tmp" 11 | fi 12 | 13 | exec docker run --rm --name jelly $OPTS --network none -v "$(readlink -f "$1")":/workspace -w /workspace jelly "${@:2}" 14 | -------------------------------------------------------------------------------- /tests/micro/arrays2.js: -------------------------------------------------------------------------------- 1 | var x = [ 2 | () => {console.log("1")}, 3 | () => {console.log("2")}, 4 | ]; 5 | x.push(() => {console.log("3")}); 6 | // var a0 = x[0]; 7 | // a0(); 8 | // var t = 1; 9 | // var a1 = x[t]; 10 | // a1(); 11 | 12 | var y = x.map(function(element, index, array) { 13 | element(); 14 | array[2](); 15 | this.p(); 16 | return () => {console.log("4")}; 17 | }, 18 | {p: function() {console.log("5")}}); 19 | var z = y[1]; 20 | z(); -------------------------------------------------------------------------------- /tests/micro/patterns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "pattern": "import " 5 | }, 6 | { 7 | "id": "2", 8 | "pattern": "read .filter" 9 | }, 10 | { 11 | "id": "3", 12 | "pattern": "call .filter" 13 | }, 14 | { 15 | "id": "4", 16 | "pattern": "call .filter()" 17 | }, 18 | { 19 | "id": "5", 20 | "pattern": "read .obj" 21 | }, 22 | { 23 | "id": "6", 24 | "pattern": "write .obj.foo" 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /tests/micro/super5.js: -------------------------------------------------------------------------------- 1 | class A { 2 | constructor() { 3 | this.qqq = () => {console.log("qqq")}; 4 | } 5 | m() { 6 | this.www = () => {console.log("www")}; 7 | } 8 | } 9 | 10 | function b() { 11 | return class B extends A { 12 | constructor() { 13 | super(); 14 | (() => { 15 | super.m(); 16 | })(); 17 | } 18 | } 19 | } 20 | 21 | var a = b(); 22 | var c = new a(); 23 | c.qqq(); 24 | c.www(); 25 | -------------------------------------------------------------------------------- /tests/approx/staticRequire.js: -------------------------------------------------------------------------------- 1 | /** All statically resolvable require calls should be collected at the AST traversal and processed, regardless of 2 | * if the dynamic execution encounters it. */ 3 | 4 | function FuncWithUnreachableCode(x) { 5 | while (x.hasNext()) { 6 | // ... 7 | } 8 | 9 | // This require is unreachable due to the infinite while loop. Yet we should still see the effects of running the 10 | // top-level code of it. 11 | const req = require('foolib') 12 | 13 | } -------------------------------------------------------------------------------- /tests/approx/hints-sandbox.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:hintsOnly/sandbox.js"],"functions":["0:18:12:20:2","0:22:13:24:2","0:26:16:28:2","0:30:18:30:41","0:36:8:36:22","0:11:22:12:2","0:41:8:41:22"],"reads":[],"writes":[{"type":"normal","loc":"0:36:1:36:22","baseLoc":"0:34:9:34:11","baseType":"Object","prop":"p","valLoc":"0:36:8:36:22","valType":"Function"},{"type":"normal","loc":"0:41:1:41:22","baseLoc":"0:34:9:34:11","baseType":"Object","prop":"p","valLoc":"0:41:8:41:22","valType":"Function"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/micro/private.js: -------------------------------------------------------------------------------- 1 | class C { 2 | #foo = () => {console.log("foo")}; 3 | 4 | #bar() { 5 | console.log("bar"); 6 | } 7 | 8 | static #baz = () => {console.log("baz")}; 9 | 10 | static #qux() { 11 | console.log("qux"); 12 | } 13 | 14 | constructor() { 15 | this.#foo(); 16 | this.#foo = () => {console.log("quux")}; 17 | this.#foo(); 18 | this.#bar(); 19 | C.#baz(); 20 | C.#qux(); 21 | } 22 | } 23 | 24 | new C() 25 | -------------------------------------------------------------------------------- /tests/approx/hints-stdlib.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:hintsOnly/stdlib.js"],"functions":["0:11:31:19:2","0:13:23:17:6","0:14:52:16:10"],"reads":[{"loc":"0:30:1:30:7","prop":"p","valLoc":"0:29:10:29:12","valType":"Object"}],"writes":[{"type":"normal","loc":"0:29:1:29:12","baseLoc":"0:28:11:28:13","baseType":"Object","prop":"p","valLoc":"0:29:10:29:12","valType":"Object"},{"type":"normal","loc":"0:37:1:37:12","baseLoc":"0:28:11:28:13","baseType":"Object","prop":"p","valLoc":"0:37:10:37:12","valType":"Object"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/micro/this.js: -------------------------------------------------------------------------------- 1 | var x = { 2 | p: function() { 3 | return this.q; 4 | }, 5 | q: function() { 6 | console.log("1"); 7 | } 8 | } 9 | var t = x.p() 10 | t(); 11 | 12 | function f() {} 13 | f.g = function() { 14 | console.log("2"); 15 | } 16 | f.h = function() { 17 | this.g(); 18 | } 19 | f.h(); 20 | 21 | const o = { 22 | foo() { 23 | return () => this.bar(); 24 | }, 25 | bar() { 26 | console.log("3"); 27 | }, 28 | }; 29 | const l = o.foo(); 30 | l(); 31 | -------------------------------------------------------------------------------- /tests/micro/prototypes3.js: -------------------------------------------------------------------------------- 1 | 2 | function Foo() {} 3 | 4 | Foo.prototype = { 5 | foo() { 6 | console.log("foo1"); 7 | }, 8 | }; 9 | 10 | const a = new Foo(); 11 | const b = Object.create(Object.getPrototypeOf(a)); 12 | b.foo(); 13 | 14 | Object.setPrototypeOf(b, { 15 | foo() { 16 | console.log("foo2"); 17 | }, 18 | }); 19 | 20 | b.foo(); 21 | 22 | 23 | class Bar { 24 | static bar() { 25 | console.log("bar"); 26 | }; 27 | }; 28 | 29 | 30 | const c = {__proto__: Bar}; 31 | c.bar(); 32 | -------------------------------------------------------------------------------- /tests/approx/hints-function.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:function.js","approx@1.0.0:function.js:eval[1:11:1:39]","approx@1.0.0:function.js:eval[4:16:4:55]"],"functions":["0:7:11:7:25"],"reads":[{"loc":"0:10:1:10:5","prop":"b","valLoc":"0:7:11:7:25","valType":"Function"}],"writes":[{"type":"normal","loc":"2:1:1:1:9","baseLoc":"0:5:11:5:13","baseType":"Object","prop":"b","valLoc":"0:7:11:7:25","valType":"Function"}],"requires":[],"evals":[{"loc":"0:1:11:1:39","str":"function anonymous(){return this;}"},{"loc":"0:4:16:4:55","str":"function anonymous(x,y,z){x[y] = z}"}]} -------------------------------------------------------------------------------- /tests/approx/srcLoc.json: -------------------------------------------------------------------------------- 1 | {"entries":["srcLoc.js"],"files":["srcLoc.js"],"functions":["0:1:1:38:26","0:3:18:5:2","0:4:20:4:28","0:15:1:17:2","0:16:21:16:43","0:14:22:14:35","0:23:17:23:40","0:23:28:23:38","0:28:1:33:2","0:30:9:30:56","0:31:10:31:60"],"calls":["0:7:11:7:23","0:10:1:10:10","0:21:2:21:25","0:21:3:21:8","0:24:9:24:18","0:25:1:25:6","0:35:9:35:14","0:37:1:37:12","0:38:1:38:26"],"fun2fun":[[0,1],[0,2],[0,3],[0,5],[0,6],[0,7],[0,8],[0,9],[0,10]],"call2fun":[[0,1],[1,2],[3,3],[2,5],[4,6],[5,7],[6,8],[7,9],[8,10]],"ignore":[],"time":"Wed, 10 Jan 2024 12:55:53 GMT"} -------------------------------------------------------------------------------- /tests/micro/defineProperty.json: -------------------------------------------------------------------------------- 1 | {"entries":["defineProperty.js"],"files":["defineProperty.js"],"functions":["0:1:1:75:1","0:3:1:23:2","0:1:1:1:17","0:12:9:14:10","0:7:9:9:10","0:25:1:47:2","0:35:13:37:14","0:30:13:32:14","0:49:1:70:2","0:58:13:60:14","0:53:13:55:14"],"calls":["0:72:1:72:10","0:17:5:17:12","0:22:5:22:9","0:73:1:73:11","0:41:5:41:12","0:46:5:46:9","0:74:1:74:9","0:64:5:64:12","0:69:5:69:9"],"fun2fun":[[0,1],[0,5],[0,8],[1,2],[5,2],[8,2]],"call2fun":[[0,1],[1,2],[2,2],[3,5],[4,2],[5,2],[6,8],[7,2],[8,2]],"ignore":[],"time":"Tue, 29 Aug 2023 14:38:09 GMT"} -------------------------------------------------------------------------------- /tests/micro/accessors4.js: -------------------------------------------------------------------------------- 1 | 2 | const obj = { 3 | baz: () => { console.log("baz"); }, 4 | get foo() { 5 | console.log("foo"); 6 | this.baz(); 7 | }, 8 | }; 9 | 10 | const x = obj.foo; 11 | 12 | function setter(v) { 13 | console.log("setter"); 14 | this.baz(); 15 | } 16 | 17 | Object.defineProperty(obj, "foo", {get: setter}); 18 | 19 | function doit(o, f) { 20 | Object.defineProperty(o, "bar", {set: setter}); 21 | f(o); 22 | } 23 | 24 | function doit2(o) { 25 | o.bar = 123; 26 | } 27 | 28 | doit(obj, doit2); 29 | -------------------------------------------------------------------------------- /tests/mochatest/test-with-hook.json: -------------------------------------------------------------------------------- 1 | {"entries":["node_modules/.bin/mocha"],"files":["node_modules/pirates/lib/index.js","require-hook.js","mylib.js"],"functions":["1:1:1:4:1","0:1:1:139:2","0:9:1:9:96","0:79:1:139:2","0:95:16:123:4","0:101:46:122:6","0:23:1:38:2","0:106:26:118:12","1:2:5:2:117","2:1:1:4:1","2:1:23:1:38","2:3:24:3:44"],"calls":["1:1:1:3:2","0:7:15:7:56","0:8:13:8:52","0:104:13:104:70","0:113:29:113:49","2:3:37:3:44"],"fun2fun":[[0,3],[1,2],[5,6],[7,8],[11,10]],"call2fun":[[1,2],[2,2],[0,3],[3,6],[4,8],[5,10]],"ignore":[],"time":"Fri, 04 Aug 2023 16:16:08 GMT"} -------------------------------------------------------------------------------- /tests/approx/deconstruction.json: -------------------------------------------------------------------------------- 1 | {"entries":["deconstruction.js"],"files":["deconstruction.js"],"functions":["0:1:1:56:2","0:4:1:9:2","0:5:20:5:33","0:5:52:5:64","0:5:70:5:83","0:7:15:7:29","0:20:1:29:2","0:21:30:24:6","0:27:12:27:26","0:33:1:38:2","0:36:12:36:26"],"calls":["0:12:21:12:31","0:13:1:13:5","0:14:1:14:8","0:15:1:15:8","0:16:1:16:4","0:31:1:31:21","0:28:5:28:10","0:40:1:40:19","0:37:5:37:10"],"fun2fun":[[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,9],[6,8],[9,10]],"call2fun":[[0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,8],[7,9],[8,10]],"ignore":[],"time":"Wed, 10 Jan 2024 12:55:18 GMT"} -------------------------------------------------------------------------------- /tests/approx/hints-proxy.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:hintsOnly/proxy.js"],"functions":["0:6:1:11:2","0:13:1:19:2","0:21:1:24:2","0:27:1:37:2","0:40:1:43:2","0:10:12:10:20","0:18:12:18:20"],"reads":[{"loc":"0:36:12:36:20","prop":"val","valLoc":"0:35:21:35:23","valType":"Object"}],"writes":[{"type":"normal","loc":"0:10:5:10:20","baseLoc":"0:9:13:9:15","baseType":"Object","prop":"p","valLoc":"0:10:12:10:20","valType":"Function"},{"type":"normal","loc":"0:18:5:18:20","baseLoc":"0:17:15:17:17","baseType":"Object","prop":"p","valLoc":"0:18:12:18:20","valType":"Function"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/micro/destructuring.json: -------------------------------------------------------------------------------- 1 | {"entries":["destructuring.js"],"files":["destructuring.js"],"functions":["0:1:1:46:1","0:6:5:8:6","0:2:8:2:32","0:4:12:4:36","0:7:16:7:40","0:10:88:10:113","0:19:5:22:6","0:27:5:27:29","0:29:9:29:33","0:40:25:40:33","0:40:35:40:43"],"calls":["0:11:1:11:5","0:12:1:12:5","0:13:1:13:5","0:14:1:14:5","0:15:1:15:5","0:16:1:16:5","0:21:9:21:12","0:33:1:33:5","0:34:1:34:5","0:38:1:38:8","0:41:1:41:4","0:42:1:42:4"],"fun2fun":[[0,2],[0,3],[0,4],[0,5],[0,7],[0,8],[0,9],[0,10],[6,2]],"call2fun":[[0,2],[1,2],[2,2],[3,3],[4,4],[5,5],[6,2],[7,7],[8,8],[9,7],[10,9],[11,10]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/super4.json: -------------------------------------------------------------------------------- 1 | {"entries":["super4.js"],"files":["super4.js"],"functions":["0:1:1:34:1","0:7:1:26:2","0:17:16:17:27","0:21:9:23:10","0:4:12:4:18","0:24:16:24:30","0:8:12:25:6","0:1:1:5:2","0:15:9:15:23","0:3:5:3:11","0:16:9:16:20","0:12:9:14:10","0:18:16:20:10"],"calls":["0:28:9:28:20","0:22:13:22:22","0:24:20:24:29","0:29:9:29:16","0:15:13:15:22","0:30:1:30:6","0:13:13:13:22","0:31:1:31:6","0:19:13:19:22"],"fun2fun":[[0,1],[0,6],[0,11],[0,12],[3,4],[5,4],[8,9],[11,9],[12,4]],"call2fun":[[0,1],[1,4],[2,4],[3,6],[4,9],[5,11],[6,9],[7,12],[8,4]],"ignore":[],"time":"Sun, 15 Sep 2024 16:16:47 GMT"} -------------------------------------------------------------------------------- /tests/micro/import1.mjs: -------------------------------------------------------------------------------- 1 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export 2 | 3 | import cube2, { cube, foo, graph, function1, function2 } from './export1.mjs'; 4 | 5 | graph.options = { 6 | color:'blue', 7 | thickness:'3px' 8 | }; 9 | 10 | graph.draw(); 11 | console.log(cube(3)); 12 | console.log(foo); 13 | 14 | console.log(cube2(3)); 15 | 16 | console.log(function1(2)); 17 | console.log(function2(2)); 18 | 19 | console.log(import.meta); 20 | 21 | // see also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import 22 | 23 | -------------------------------------------------------------------------------- /tests/micro/assign2.js: -------------------------------------------------------------------------------- 1 | 2 | const o = Object.assign({ 3 | set foo(x) { 4 | console.log("set foo", x); 5 | this._foo = x; 6 | }, 7 | }, { 8 | get foo() { 9 | console.log("get foo 1"); 10 | return this; 11 | }, 12 | }, Object.create({ 13 | // properties on prototype are not transferred 14 | bar() { console.log("bar"); }, 15 | }, { 16 | foo: { 17 | get: function() { 18 | console.log("get foo 2"); 19 | return this; 20 | }, 21 | enumerable: true, 22 | }, 23 | })); 24 | 25 | o.bar?.(); 26 | o._foo.bar(); 27 | -------------------------------------------------------------------------------- /tests/micro/arguments.js: -------------------------------------------------------------------------------- 1 | // Move f1 to 2nd line to make it discernible from synthetic module function 2 | function f1(x) { 3 | console.log("0"); 4 | if (!x) 5 | return; 6 | arguments[0](); 7 | arguments[1](); 8 | arguments[0] = () => {console.log("3")}; 9 | x(); // TODO: assignments to arguments 10 | arguments.callee(); // TODO: arguments.callee 11 | } 12 | f1(() => {console.log("1")}, () => {console.log("2")}); 13 | 14 | function f2() { 15 | const f = () => arguments[0]; // arrow functions don't have their own 'arguments' 16 | f()(); 17 | } 18 | f2(() => {console.log("4")}); 19 | -------------------------------------------------------------------------------- /tests/approx/hints-staticRequire.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:staticRequire.js","foolib@1.0.0:index.js"],"functions":["0:4:1:13:2","1:6:10:6:34","1:11:16:14:2"],"reads":[{"loc":"1:7:9:7:15","prop":"baz","valLoc":"1:6:10:6:34","valType":"Function"},{"loc":"1:12:5:12:11","prop":"baz","valLoc":"1:6:10:6:34","valType":"Function"}],"writes":[{"type":"normal","loc":"1:6:1:6:34","baseLoc":"1:5:9:5:11","baseType":"Object","prop":"baz","valLoc":"1:6:10:6:34","valType":"Function"},{"type":"normal","loc":"1:11:1:14:2","baseLoc":"1:-1:-1:-1:-1","baseType":"Object","prop":"bar","valLoc":"1:11:16:14:2","valType":"Function"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/micro/export1.mjs: -------------------------------------------------------------------------------- 1 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export 2 | 3 | export { default as function1, 4 | function2 } from './export2.mjs'; 5 | 6 | function cube(x) { 7 | return x * x * x; 8 | } 9 | 10 | const foo = Math.PI + Math.SQRT2; 11 | 12 | var graph = { 13 | options: { 14 | color:'white', 15 | thickness:'2px' 16 | }, 17 | draw: function() { 18 | console.log('From graph draw function'); 19 | } 20 | } 21 | 22 | export { cube, foo, graph }; 23 | 24 | export default function cube2(x) { 25 | return x * x * x; 26 | } 27 | -------------------------------------------------------------------------------- /tests/micro/mods/main.js: -------------------------------------------------------------------------------- 1 | (async () => { 2 | const { callEsm } = await import('./esm.mjs'); 3 | const result = await callEsm('World1'); 4 | console.log(result); 5 | })(); 6 | 7 | (async () => { 8 | const { callEsm } = await import('pkg-esm'); 9 | const result = callEsm('World2'); 10 | console.log(result); 11 | })(); 12 | 13 | (async () => { 14 | const { callEsm } = require('./esm.mjs'); 15 | const result = callEsm('World3'); 16 | console.log(result); 17 | })(); 18 | 19 | (async () => { 20 | const { callEsm } = require('pkg-esm'); 21 | const result = callEsm('World4'); 22 | console.log(result); 23 | })(); 24 | -------------------------------------------------------------------------------- /tests/approx/packageStructure/test/some.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var obj = require('../index') 3 | 4 | describe("test suite", function () { 5 | it("test", function() { 6 | /** This test will produce hints if executed. */ 7 | const x = {} 8 | const y = "p" 9 | const z = {} 10 | 11 | let res = obj.Foo(x, y, z); 12 | assert.equal(res, x) 13 | assert.equal(res.p, z) 14 | }) 15 | 16 | it("function call", function () { 17 | const x = {} 18 | const y = "p1" 19 | const z = function () {} 20 | let res = obj.Foo(x,y,z) 21 | 22 | res.p1(); 23 | 24 | }) 25 | }) -------------------------------------------------------------------------------- /tests/micro/spread.json: -------------------------------------------------------------------------------- 1 | {"entries":["spread.js"],"files":["spread.js"],"functions":["0:1:1:36:1","0:1:1:5:2","0:7:5:7:29","0:8:5:8:29","0:11:10:11:34","0:13:17:13:42","0:13:55:13:80","0:19:12:19:37","0:19:46:19:71"],"calls":["0:11:1:11:35","0:2:5:2:9","0:3:5:3:9","0:4:5:4:9","0:14:1:14:7","0:15:1:15:7","0:16:1:16:7","0:17:1:17:7","0:20:1:20:7","0:21:1:21:7","0:22:1:22:7","0:23:1:23:7","0:26:1:26:8","0:27:1:27:8","0:28:1:28:8","0:29:1:29:8","0:32:1:32:8","0:33:1:33:8","0:34:1:34:8","0:35:1:35:8"],"fun2fun":[[0,1],[0,5],[0,6],[0,2],[0,3],[0,7],[0,8],[1,2],[1,3],[1,4]],"call2fun":[[0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,2],[7,3],[8,7],[9,2],[10,3],[11,8],[12,5],[13,6],[14,2],[15,3],[16,7],[17,2],[18,3],[19,8]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/super4.js: -------------------------------------------------------------------------------- 1 | class A { 2 | constructor() {} 3 | m() {} 4 | static s() {} 5 | } 6 | 7 | function postMixin() { 8 | return class PostMixin extends A { 9 | constructor() { 10 | super(); 11 | } 12 | m() { 13 | super.m(); 14 | } 15 | w = super.m(); 16 | eee = this; 17 | static fff = this; 18 | static s() { 19 | super.s(); 20 | } 21 | static { 22 | super.s(); 23 | } 24 | static q = super.s(); 25 | } 26 | } 27 | 28 | var a = postMixin(); 29 | var x = new a(); 30 | x.m(); 31 | a.s(); 32 | console.log(x.eee === x); 33 | console.log(a.fff === a); 34 | -------------------------------------------------------------------------------- /tests/micro/super.json: -------------------------------------------------------------------------------- 1 | {"entries":["super.js"],"files":["super.js"],"functions":["0:1:1:70:1","0:11:12:14:2","0:35:12:35:24","0:36:5:39:6","0:11:16:13:6","0:16:1:40:2","0:1:1:14:2","0:18:15:20:10","0:5:5:7:6","0:25:5:29:6","0:30:12:34:6","0:8:12:10:6","0:53:5:57:6","0:48:5:50:6","0:62:5:66:6"],"calls":["0:37:9:37:18","0:42:9:42:16","0:3:9:3:12","0:22:9:22:18","0:43:1:43:6","0:27:9:27:18","0:44:1:44:6","0:32:9:32:18","0:45:1:45:6","0:60:1:60:8","0:55:9:55:19","0:69:1:69:8","0:64:9:64:19"],"fun2fun":[[0,5],[0,9],[0,10],[0,4],[0,12],[0,14],[3,4],[5,8],[6,7],[9,8],[10,11],[12,13],[14,13]],"call2fun":[[0,4],[1,5],[2,7],[3,8],[4,9],[5,8],[6,10],[7,11],[8,4],[9,12],[10,13],[11,14],[12,13]],"ignore":[],"time":"Sun, 29 Oct 2023 07:50:02 GMT"} -------------------------------------------------------------------------------- /tests/micro/call-expressions.js: -------------------------------------------------------------------------------- 1 | (function(){})(); 2 | var x = function(){}(); 3 | var y = (function(){}()); 4 | (function(){}()); 5 | ( (function(){}) )(); 6 | (( (function(){}) )()); 7 | (( (function(){})() )); 8 | ( () /* hello */ => void 0)(/* world */); 9 | ( (() => void 0)() ); 10 | function f() {} 11 | f(); 12 | (f)(); 13 | ((f))(); 14 | ((f)()); 15 | (((f))()); 16 | (( (/* */(f))))(); 17 | (f)(({} /* comment */)); 18 | (f()); 19 | ((f())); 20 | ( f() ); 21 | const o = {f}; 22 | o.f(); 23 | (o.f()); 24 | ((o.f())); 25 | (o.f)(); 26 | ((o.f)()); 27 | (((o.f)())); 28 | o?.f(); 29 | (o?.f()); 30 | ((o?.f())); 31 | new f(); 32 | (new f()); 33 | ((new f())); 34 | new (f)(); 35 | (new (f)()); 36 | ((new (f)())); 37 | (new ((f))()); 38 | -------------------------------------------------------------------------------- /tests/approx/dynamic.js: -------------------------------------------------------------------------------- 1 | /** Writes between two known objects prior to eval statement should still produce useful hints. */ 2 | 3 | const x1 = {}; 4 | const x2 = function foo() {console.log("@@@")} 5 | 6 | eval(` 7 | const p = "p"; 8 | x1[p] = x2; 9 | `) 10 | x1.p(); 11 | 12 | var x3 = {prop: undefined} 13 | var x4 = function bar() {console.log("!!!")} 14 | eval(`x3.prop = x4`) 15 | x3.prop(); 16 | 17 | 18 | /** A dynamic property read produces hints even if the value came from an eval. */ 19 | var x5 = {}; 20 | const v = "val"; 21 | const x6 = function bar() {console.log("Hi!")} 22 | eval(`x5 = {val: x6}`) 23 | x5[v](); 24 | 25 | /** Dynamic requires should be recorded and used. */ 26 | const str = "foo" + "lib"; 27 | require(str); -------------------------------------------------------------------------------- /tests/approx/hints-newNative.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:newNative.js","approx@1.0.0:newNative.js:eval[7:20:7:48]"],"functions":["0:4:20:4:49","0:9:25:9:39"],"reads":[{"loc":"0:9:3:9:19","prop":"foobar","valLoc":"0:7:20:7:48","valType":"Function"}],"writes":[{"type":"normal","loc":"0:4:1:4:50","baseLoc":"0:1:11:1:13","baseType":"Object","prop":"p","valLoc":"0:4:8:4:50","valType":"Object"},{"type":"normal","loc":"0:7:1:7:48","baseLoc":"0:6:13:6:22","baseType":"Object","prop":"foobar","valLoc":"0:7:20:7:48","valType":"Function"},{"type":"normal","loc":"0:9:1:9:39","baseLoc":"0:1:11:1:13","baseType":"Object","prop":"baz","valLoc":"0:9:25:9:39","valType":"Function"}],"requires":[],"evals":[{"loc":"0:7:20:7:48","str":"function anonymous(){return 'baz'}"}]} -------------------------------------------------------------------------------- /tests/micro/super2.js: -------------------------------------------------------------------------------- 1 | class A { 2 | m() { 3 | var amthis = this; // amthis === x 4 | console.log("Am", amthis); 5 | } 6 | static s() { 7 | var asthis = this; // asthis === B 8 | console.log("As", asthis); 9 | } 10 | } 11 | 12 | class B extends A { 13 | m() { 14 | super.m(); 15 | var bmthis = this; // bmthis === x 16 | console.log("Bm", bmthis); 17 | super.foo = () => {}; // behaves like this.foo = ... 18 | } 19 | static s() { 20 | super.s(); 21 | var bsthis = this; // bsthis === B 22 | console.log("Bs", bsthis); 23 | } 24 | } 25 | 26 | var x = new B(); 27 | x.m(); 28 | B.s(); 29 | console.log(x.hasOwnProperty("foo")); 30 | -------------------------------------------------------------------------------- /tests/micro/fun2.js: -------------------------------------------------------------------------------- 1 | class C { 2 | [f()]() { // this call belongs to the top-level module code 3 | console.log("Hello World! from " + f()); // this call to f belongs to the 'foo' method 4 | } 5 | 6 | bar(x = g()) { // this call belongs to the 'bar' method 7 | console.log("Hello " + g() + " from bar"); // this call to g belongs to the 'bar' method 8 | } 9 | 10 | baz = h() // this call belongs to the C constructor 11 | 12 | static qux = i() // this call belongs to the top-level module code 13 | } 14 | 15 | function f() { 16 | return "foo"; 17 | } 18 | 19 | function g() { 20 | return "World!"; 21 | } 22 | 23 | function h() {} 24 | 25 | function i() {} 26 | 27 | var x = new C; 28 | x.foo(); 29 | x.bar(); 30 | -------------------------------------------------------------------------------- /tests/approx/hints-packageStructure.json: -------------------------------------------------------------------------------- 1 | {"modules":["packagestructure@1.0.0:index.js","packagestructure@1.0.0:test/some.test.js"],"functions":["0:1:2:15:2","0:5:19:8:6","0:10:5:14:6","1:4:24:25:2","1:5:16:14:6","1:16:25:24:6","1:19:19:19:33"],"reads":[{"loc":"0:13:13:13:17","prop":"p1","valLoc":"1:19:19:19:33","valType":"Function"}],"writes":[{"type":"normal","loc":"0:5:5:8:6","baseLoc":"0:3:32:3:34","baseType":"Object","prop":"Foo","valLoc":"0:5:19:8:6","valType":"Function"},{"type":"normal","loc":"0:11:9:11:17","baseLoc":"1:7:19:7:21","baseType":"Object","prop":"p","valLoc":"1:9:19:9:21","valType":"Object"},{"type":"normal","loc":"0:11:9:11:17","baseLoc":"1:17:19:17:21","baseType":"Object","prop":"p1","valLoc":"1:19:19:19:33","valType":"Function"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/npm-packages/jelly.test.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import assert from "assert"; 4 | import {runTest} from "../../src/testing/runtest"; 5 | import {expand} from "../../src/misc/files"; 6 | import {options} from "../../src/options"; 7 | 8 | describe("tests/npm-packages", () => { 9 | describe.each(Object.entries(JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf-8")).dependencies))( 10 | "%s/%s", (name: string) => { 11 | const pkgdir = path.join(__dirname, "node_modules", name); 12 | assert(fs.existsSync(pkgdir)); 13 | 14 | options.basedir = "tests/npm-packages"; // for expand 15 | runTest("tests/npm-packages", expand(pkgdir), { }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /tests/approx/esm.mjs: -------------------------------------------------------------------------------- 1 | import {setProperty} from "./node_modules/esm/lib.mjs" 2 | import fs from 'fs' 3 | 4 | import * as foo from 'foolib' 5 | 6 | const x = {} 7 | const y = "p" 8 | const z = {} 9 | setProperty(x, y, z) 10 | 11 | // fs is monkey patched. 12 | const fd = fs.openSync("qwe", "w") 13 | fs.writeSync(fd, "foobar") 14 | fs.closeSync(fd); 15 | 16 | 17 | const a = {foo: function () {}} 18 | foo.default.bar(a) 19 | 20 | import {asyncFoo} from "./node_modules/esm/lib.mjs" 21 | async function someName() { 22 | await asyncFoo(); 23 | const x = {} 24 | x["fromSomeName"] = function () {} 25 | return x; 26 | } 27 | 28 | someName().then(r => r.fromSomeName()); 29 | 30 | export function otherName(x, y) { 31 | x.y.z.a.b.c().e().f(); 32 | y[x.y()]; 33 | const a = {} 34 | a["p"+"1"] = {} 35 | } -------------------------------------------------------------------------------- /tests/micro/asyncawait.json: -------------------------------------------------------------------------------- 1 | {"entries":["asyncawait.js"],"files":["asyncawait.js"],"functions":["0:1:1:58:1","0:1:2:57:2","0:3:27:7:6","0:4:17:6:10","0:12:23:12:50","0:15:16:17:6","0:16:16:16:44","0:21:16:23:6","0:28:16:31:6","0:40:16:43:6","0:24:15:26:6","0:22:16:22:44","0:33:20:35:6","0:29:15:29:44","0:36:20:38:6","0:30:16:30:45","0:46:13:48:6","0:41:17:41:46","0:49:20:51:6","0:42:16:42:45"],"calls":["0:1:1:57:5","0:10:5:10:9","0:13:5:13:9","0:18:22:18:26","0:19:5:19:9","0:24:5:24:9","0:32:16:32:20","0:44:16:44:20","0:53:27:53:31","0:25:9:25:13","0:34:9:34:20","0:37:9:37:20","0:47:9:47:20","0:54:9:54:12","0:50:9:50:20"],"fun2fun":[[0,1],[1,3],[1,4],[1,5],[1,6],[1,7],[1,8],[1,9],[1,17],[10,11],[12,13],[14,15],[16,17],[18,19]],"call2fun":[[0,1],[1,3],[2,4],[3,5],[4,6],[5,7],[6,8],[7,9],[8,9],[9,11],[10,13],[11,15],[12,17],[13,17],[14,19]],"ignore":[]} -------------------------------------------------------------------------------- /tests/approx/this.json: -------------------------------------------------------------------------------- 1 | {"entries":["this.js"],"files":["this.js"],"functions":["0:1:1:70:14","0:2:1:5:2","0:4:18:4:32","0:12:5:14:16","0:11:1:21:2","0:23:17:24:2","0:18:5:20:6","0:19:28:19:42","0:31:1:34:2","0:32:15:32:32","0:39:1:43:2","0:41:16:41:30","0:48:5:53:2","0:47:1:53:2","0:48:14:52:6","0:49:17:49:31","0:50:24:50:38","0:60:1:68:2","0:66:27:66:41"],"calls":["0:7:11:7:20","0:8:1:8:8","0:23:11:24:3","0:25:1:25:6","0:26:1:26:11","0:27:1:27:8","0:36:11:36:20","0:37:1:37:4","0:45:1:45:10","0:45:1:45:8","0:55:11:55:27","0:55:11:55:18","0:56:1:56:4","0:57:1:57:7","0:70:1:70:13","0:70:1:70:8"],"fun2fun":[[0,1],[0,2],[0,4],[0,5],[0,6],[0,7],[0,8],[0,9],[0,10],[0,11],[0,13],[0,14],[0,15],[0,16],[0,17],[0,18]],"call2fun":[[0,1],[1,2],[2,4],[3,5],[4,6],[5,7],[6,8],[7,9],[9,10],[8,11],[11,13],[10,14],[12,15],[13,16],[15,17],[14,18]],"ignore":[],"time":"Wed, 10 Jan 2024 12:56:07 GMT"} -------------------------------------------------------------------------------- /tests/approx/computedProperties.json: -------------------------------------------------------------------------------- 1 | {"entries":["computedProperties.js"],"files":["computedProperties.js"],"functions":["0:1:1:79:21","0:5:24:5:41","0:9:10:9:44","0:13:10:13:45","0:19:5:20:6","0:35:12:35:60","0:29:5:31:16","0:26:1:43:2","0:35:29:35:59","0:37:5:37:36","0:39:5:39:38","0:45:17:45:50","0:40:5:40:35","0:50:11:50:41","0:29:28:29:58","0:36:12:36:47","0:42:5:42:23","0:60:19:60:49","0:61:9:63:10","0:67:30:67:60","0:71:9:71:39","0:72:9:72:42"],"calls":["0:6:1:6:8","0:22:1:22:14","0:45:11:45:51","0:46:1:46:12","0:47:1:47:11","0:49:1:49:4","0:51:1:51:10","0:52:1:52:21","0:53:1:53:12","0:54:1:54:9","0:75:1:75:13","0:76:1:76:13","0:77:1:77:25"],"fun2fun":[[0,1],[0,4],[0,7],[0,8],[0,9],[0,11],[0,13],[0,14],[0,15],[0,16],[0,17],[0,18],[0,19]],"call2fun":[[0,1],[1,4],[2,7],[3,8],[4,9],[5,11],[6,13],[7,14],[8,15],[9,16],[10,17],[11,18],[12,19]],"ignore":[],"time":"Wed, 10 Jan 2024 12:55:12 GMT"} -------------------------------------------------------------------------------- /tests/micro/fun.js: -------------------------------------------------------------------------------- 1 | var x = {a: function() { console.log("1"); }}; 2 | var f = function() {return this.a;}.bind(x); 3 | f()(); 4 | 5 | function foo(b) {return this(b);} 6 | (foo.call((a) => a, () => { console.log("2"); }))(); 7 | 8 | function bar(c) {return this(c);} 9 | function baz() { 10 | return bar.apply((d) => d, arguments); 11 | } 12 | var q = baz(() => { console.log("3"); }); 13 | q(); 14 | function baz2(...args) { 15 | return bar.apply((d) => d, args); 16 | } 17 | var q2 = baz2(() => { console.log("4"); }); 18 | q2(); 19 | function baz3(a) { 20 | return bar.apply((d) => d, [a]); 21 | } 22 | var q3 = baz3(() => { console.log("5"); }); 23 | q3(); 24 | (baz3(() => { console.log("5"); })()); 25 | function baz4(f) { 26 | const a = []; 27 | a.push(f); 28 | return bar.apply((d) => d, a); 29 | } 30 | var q4 = baz4(() => { console.log("6"); }); 31 | q4(); 32 | -------------------------------------------------------------------------------- /tests/approx/hints-srcLoc.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:srcLoc.js"],"functions":["0:3:18:5:2","0:4:20:4:28","0:15:1:17:2","0:16:21:16:43","0:14:22:14:35","0:23:17:23:40","0:23:28:23:38","0:28:1:33:2","0:30:9:30:56","0:31:9:31:60"],"reads":[{"loc":"0:10:2:10:6","prop":"val","valLoc":"0:4:20:4:28","valType":"Function"},{"loc":"0:21:3:21:22","prop":"newVal","valLoc":"0:14:22:14:35","valType":"Function"},{"loc":"0:37:1:37:10","prop":"MyFunction","valLoc":"0:30:9:30:56","valType":"Function"},{"loc":"0:38:1:38:24","prop":"MyOtherFunction","valLoc":"0:31:9:31:60","valType":"Function"}],"writes":[{"type":"normal","loc":"0:11:1:11:14","baseLoc":"0:4:13:4:30","baseType":"Object","prop":"p","valLoc":"0:11:10:11:12","valType":"Object"},{"type":"normal","loc":"0:30:9:30:56","baseLoc":"0:29:12:32:6","baseType":"Object","prop":"MyFunction","valLoc":"0:30:9:30:56","valType":"Function"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /src/misc/timer.ts: -------------------------------------------------------------------------------- 1 | import {options} from "../options"; 2 | 3 | const hrtime = process.hrtime; 4 | 5 | export default class Timer { 6 | 7 | startTime: bigint; 8 | 9 | constructor() { 10 | this.startTime = hrtime.bigint(); 11 | } 12 | 13 | /** 14 | * Returns the elapsed time in nanoseconds since the timer was created. 15 | */ 16 | elapsed(): bigint { 17 | return hrtime.bigint() - this.startTime; 18 | } 19 | 20 | checkTimeout() { 21 | if (options.timeout && this.elapsed() > BigInt(options.timeout) * 1000000000n) 22 | throw new TimeoutException(); 23 | } 24 | } 25 | 26 | export class TimeoutException extends Error { 27 | 28 | constructor() { 29 | super("Analysis time limit exceeded"); 30 | } 31 | } 32 | 33 | export function nanoToMs(n: bigint): string { 34 | return `${n / 1000000n}ms`; 35 | } 36 | -------------------------------------------------------------------------------- /tests/micro/spread.js: -------------------------------------------------------------------------------- 1 | function f(a1, a2, a3) { 2 | a1(); 3 | a2(); 4 | a3(); 5 | } 6 | const xs = [ 7 | () => {console.log("1")}, 8 | () => {console.log("2")} 9 | 10 | ]; 11 | f(...xs, () => {console.log("3")}) // spread in arguments (values from iterable) 12 | 13 | const q = { p1: () => {console.log("10")}, ...xs, p2: () => {console.log("11")} }; // spread in object (properties of object) 14 | q.p1(); 15 | q.p2(); 16 | q[0](); 17 | q[1](); 18 | 19 | const w = [() => {console.log("20")}, ...xs, () => {console.log("21")}]; // spread in array (values from iterable) 20 | w[0](); 21 | w[1](); 22 | w[2](); 23 | w[3](); 24 | 25 | const q2 = {...q}; // spread in object (properties of object) 26 | q2.p1(); 27 | q2.p2(); 28 | q2[0](); 29 | q2[1](); 30 | 31 | const w2 = [...w.values()]; // spread in array (values from iterable) 32 | w2[0](); 33 | w2[1](); 34 | w2[2](); 35 | w2[3](); 36 | -------------------------------------------------------------------------------- /tests/approx/hintsOnly/asyncGenerator.js: -------------------------------------------------------------------------------- 1 | const x = {} 2 | 3 | /** Support for async function in forced execution. */ 4 | async function foo() { 5 | const p = 'p'; 6 | x[p] = function () {} 7 | } 8 | 9 | 10 | /** Support for generator functions both in traditional and forced execution. */ 11 | function* bar() { 12 | const p = 'p'; 13 | x[p] = {} 14 | } 15 | 16 | function* baz() { 17 | const p = 'p' 18 | x[p] = {} 19 | yield x; 20 | x[p+p] = {} 21 | yield x; 22 | } 23 | 24 | const gen = baz(); 25 | gen.next() 26 | gen.next() 27 | 28 | /** Support for async generator functions. */ 29 | async function* qwe() { 30 | const p = 'p' 31 | x[p] = {} 32 | } 33 | async function* qwe2() { 34 | const p = 'p' 35 | x[p] = {} 36 | yield x; 37 | x[p+p] = {} 38 | yield x; 39 | } 40 | 41 | const gen2 = qwe2(); 42 | gen2.next().then(); 43 | gen2.next().then() 44 | 45 | -------------------------------------------------------------------------------- /tests/approx/natives.json: -------------------------------------------------------------------------------- 1 | {"entries":["natives.js"],"files":["natives.js"],"functions":["0:1:1:103:1","0:4:8:5:6","0:25:5:25:18","0:14:10:15:6","0:18:10:19:6","0:20:10:21:6","0:40:10:41:6","0:43:22:44:10","0:60:1:60:18","0:68:26:68:42","0:68:44:68:60","0:74:23:74:31","0:74:33:74:41","0:81:11:81:26","0:80:11:80:26","0:94:24:94:46","0:93:12:93:26","0:98:7:98:21"],"calls":["0:10:1:10:9","0:31:1:31:9","0:32:1:32:9","0:33:1:33:9","0:52:1:52:7","0:55:1:55:9","0:56:1:56:16","0:64:1:64:12","0:71:1:71:13","0:72:1:72:13","0:76:1:76:13","0:77:1:77:13","0:84:1:84:13","0:85:1:85:13","0:90:1:90:13","0:91:1:91:13","0:96:1:96:16","0:101:1:101:13"],"fun2fun":[[0,1],[0,3],[0,4],[0,5],[0,6],[0,7],[0,8],[0,9],[0,10],[0,11],[0,12],[0,13],[0,14],[0,16],[0,17]],"call2fun":[[0,1],[1,3],[2,4],[3,5],[4,6],[5,6],[6,7],[7,8],[8,9],[9,10],[10,11],[11,12],[12,13],[13,14],[14,14],[15,13],[16,16],[17,17]],"ignore":[],"time":"Wed, 10 Jan 2024 12:55:39 GMT"} -------------------------------------------------------------------------------- /tests/micro/destructuring.js: -------------------------------------------------------------------------------- 1 | var x1 = { 2 | a: () => {console.log("1")}, 3 | b: { 4 | c: () => {console.log("2")}, 5 | }, 6 | get bar() { 7 | return () => {console.log("3")}; 8 | } 9 | }; 10 | var {a: y1 = () => {console.log("1b")}, ["a"]: y2, a: y3, b: {c: y4}, bar: y5, d: y6 = () => {console.log("1c")}} = x1; 11 | y1(); 12 | y2(); 13 | y3(); 14 | y4(); 15 | y5(); 16 | y6(); 17 | 18 | let c = { 19 | set foo(q) { 20 | console.log("4"); 21 | q(); 22 | } 23 | }; 24 | ({a: c.foo} = x1); 25 | 26 | var x2 = [ 27 | () => {console.log("5")}, 28 | [ 29 | () => {console.log("6")} 30 | ] 31 | ]; 32 | var [z1, [z2]] = x2; 33 | z1(); 34 | z2(); 35 | 36 | let d = {}; 37 | [d.baz] = x2; 38 | d.baz(); 39 | 40 | const [x, y] = new Set([() => {}, () => {}]); 41 | x(); 42 | y(); 43 | 44 | // const {a,...others} = {a:1,b:2,c:3}; 45 | // const [a2,...others2] = [1,2,3]; 46 | -------------------------------------------------------------------------------- /tests/approx/hints-library.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:library.js","foolib@1.0.0:index.js"],"functions":["1:6:10:6:34","0:7:10:7:34","1:11:16:14:2"],"reads":[{"loc":"1:7:9:7:15","prop":"baz","valLoc":"1:6:10:6:34","valType":"Function"},{"loc":"0:8:9:8:15","prop":"foo","valLoc":"0:7:10:7:34","valType":"Function"},{"loc":"0:11:1:11:9","prop":"bar","valLoc":"1:11:16:14:2","valType":"Function"},{"loc":"1:12:5:12:11","prop":"baz","valLoc":"1:6:10:6:34","valType":"Function"},{"loc":"1:13:5:13:11","prop":"foo","valLoc":"0:7:10:7:34","valType":"Function"}],"writes":[{"type":"normal","loc":"1:6:1:6:34","baseLoc":"1:5:9:5:11","baseType":"Object","prop":"baz","valLoc":"1:6:10:6:34","valType":"Function"},{"type":"normal","loc":"1:11:1:14:2","baseLoc":"1:-1:-1:-1:-1","baseType":"Object","prop":"bar","valLoc":"1:11:16:14:2","valType":"Function"},{"type":"normal","loc":"0:7:1:7:34","baseLoc":"0:6:9:6:11","baseType":"Object","prop":"foo","valLoc":"0:7:10:7:34","valType":"Function"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/approx/simple.json: -------------------------------------------------------------------------------- 1 | {"entries":["simple.js"],"files":["simple.js"],"functions":["0:1:1:101:8","0:4:14:4:28","0:18:10:18:18","0:17:1:17:18","0:29:1:29:11","0:41:14:41:28","0:42:18:42:32","0:45:1:47:2","0:46:6:46:31","0:55:1:58:2","0:56:5:56:27","0:57:5:57:40","0:67:1:71:2","0:66:1:66:11","0:85:1:89:2","0:80:1:84:2","0:86:5:88:6","0:81:5:83:6","0:92:13:92:30","0:100:16:100:29"],"calls":["0:11:1:11:7","0:12:1:12:8","0:13:1:13:11","0:23:1:23:12","0:24:1:24:11","0:31:10:31:19","0:32:12:32:19","0:34:1:34:8","0:36:1:36:19","0:49:1:49:8","0:50:1:50:8","0:51:1:51:21","0:51:1:51:8","0:59:10:59:15","0:73:10:73:19","0:74:10:74:15","0:77:1:77:9","0:91:11:91:19","0:93:1:93:19","0:87:14:87:33","0:94:1:94:6","0:101:1:101:7"],"fun2fun":[[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[0,8],[0,9],[0,12],[0,14],[0,16],[0,18],[0,19],[16,17]],"call2fun":[[0,1],[1,1],[2,1],[3,2],[4,3],[5,3],[6,4],[7,2],[8,2],[9,5],[10,6],[12,7],[11,8],[13,9],[14,3],[15,12],[16,1],[17,14],[18,16],[19,17],[20,18],[21,19]],"ignore":[],"time":"Wed, 10 Jan 2024 12:55:46 GMT"} -------------------------------------------------------------------------------- /tests/micro/fun.json: -------------------------------------------------------------------------------- 1 | {"entries":["fun.js"],"files":["fun.js"],"functions":["0:1:1:32:1","0:2:9:2:36","0:1:13:1:45","0:5:1:5:34","0:6:11:6:19","0:6:21:6:48","0:9:1:11:2","0:8:1:8:34","0:10:22:10:30","0:12:13:12:40","0:14:1:16:2","0:15:22:15:30","0:17:15:17:42","0:19:1:21:2","0:20:22:20:30","0:22:15:22:42","0:24:7:24:34","0:25:1:29:2","0:28:22:28:30","0:30:15:30:42"],"calls":["0:3:1:3:6","0:3:1:3:4","0:6:1:6:52","0:6:1:6:50","0:5:25:5:32","0:12:9:12:41","0:10:12:10:42","0:8:25:8:32","0:13:1:13:4","0:17:10:17:43","0:15:12:15:37","0:18:1:18:5","0:22:10:22:43","0:20:12:20:36","0:23:1:23:5","0:24:1:24:38","0:24:2:24:35","0:30:10:30:43","0:28:12:28:34","0:31:1:31:5"],"fun2fun":[[0,1],[0,2],[0,3],[0,5],[0,6],[0,9],[0,10],[0,12],[0,13],[0,15],[0,16],[0,17],[0,19],[3,4],[6,7],[7,8],[7,11],[7,14],[7,18],[10,7],[13,7],[17,7]],"call2fun":[[1,1],[0,2],[3,3],[4,4],[2,5],[5,6],[6,7],[7,8],[7,11],[7,14],[7,18],[8,9],[9,10],[10,7],[11,12],[12,13],[13,7],[14,15],[16,13],[15,16],[17,17],[18,7],[19,19]],"ignore":[],"time":"Wed, 24 Jan 2024 14:14:47 GMT"} -------------------------------------------------------------------------------- /src/misc/memory.ts: -------------------------------------------------------------------------------- 1 | import {options} from "../options"; 2 | import assert from "assert"; 3 | import * as v8 from "v8"; 4 | import logger, {writeStdOutIfActive} from "./logger"; 5 | 6 | /** 7 | * Triggers garbage collection if option --gc is enabled and returns the current size of heap used in MB. 8 | */ 9 | export function getMemoryUsage(): number { 10 | if (options.gc) { 11 | assert(typeof gc === "function"); 12 | writeStdOutIfActive("Garbage collecting..."); 13 | gc(); 14 | gc(); // running a second time sometimes finds more garbage 15 | } 16 | const res = Math.ceil(process.memoryUsage().heapUsed / 1048576); 17 | if ((options.gc && options.printProgress && logger.isInfoEnabled()) || logger.isVerboseEnabled()) 18 | logger.info(`Memory usage: ${res}MB`); 19 | return res; 20 | } 21 | 22 | /** 23 | * Returns the heap size limit in MB. 24 | */ 25 | export function getMemoryLimit(): number { 26 | return Math.ceil(v8.getHeapStatistics().heap_size_limit / 1048576); 27 | } 28 | -------------------------------------------------------------------------------- /tests/micro/rest.json: -------------------------------------------------------------------------------- 1 | {"entries":["rest.js"],"files":["rest.js"],"functions":["0:1:1:79:1","0:7:34:7:58","0:3:5:3:29","0:4:5:4:29","0:5:5:5:29","0:31:1:38:2","0:40:5:40:30","0:41:5:41:30","0:42:5:42:30","0:43:5:43:30","0:46:1:53:2","0:55:5:55:30","0:56:5:56:30","0:57:5:57:30","0:58:5:58:30","0:67:28:67:53","0:63:9:63:34","0:64:9:64:34","0:74:1:77:2","0:65:9:65:34"],"calls":["0:10:1:10:5","0:11:1:11:5","0:15:1:15:5","0:16:1:16:5","0:21:1:21:5","0:22:1:22:5","0:26:1:26:5","0:27:1:27:5","0:39:1:44:2","0:32:5:32:9","0:33:5:33:9","0:34:5:34:14","0:35:5:35:14","0:54:1:59:2","0:47:5:47:9","0:48:5:48:9","0:49:5:49:15","0:50:5:50:15","0:70:1:70:5","0:71:1:71:6","0:72:1:72:11","0:78:1:78:8","0:75:5:75:11","0:76:5:76:16"],"fun2fun":[[0,1],[0,2],[0,3],[0,4],[0,5],[0,10],[0,15],[0,16],[0,17],[0,18],[5,6],[5,7],[5,8],[5,9],[10,11],[10,12],[10,13],[10,14],[18,15],[18,19]],"call2fun":[[0,1],[1,2],[2,3],[3,4],[4,1],[5,2],[6,3],[7,4],[8,5],[9,6],[10,7],[11,8],[12,9],[13,10],[14,11],[15,12],[16,13],[17,14],[18,15],[19,16],[20,17],[21,18],[22,15],[23,19]],"ignore":[]} -------------------------------------------------------------------------------- /tests/approx/hints-conditional.json: -------------------------------------------------------------------------------- 1 | {"modules":["
:tests/approx/hintsOnly/conditional.js"],"functions":["0:53:1:58:2","0:5:1:12:2","0:14:1:19:2","0:21:1:40:2","0:42:1:48:2","0:63:1:71:2"],"reads":[],"writes":[{"type":"normal","loc":"0:57:5:57:15","baseLoc":"0:56:14:56:16","baseType":"Object","prop":"p","valLoc":"0:57:13:57:15","valType":"Object"},{"type":"normal","loc":"0:8:9:8:19","baseLoc":"0:6:14:6:16","baseType":"Object","prop":"p","valLoc":"0:8:17:8:19","valType":"Object"},{"type":"normal","loc":"0:17:9:17:19","baseLoc":"0:15:16:15:18","baseType":"Object","prop":"p","valLoc":"0:17:17:17:19","valType":"Object"},{"type":"normal","loc":"0:25:13:25:23","baseLoc":"0:22:16:22:18","baseType":"Object","prop":"q","valLoc":"0:25:21:25:23","valType":"Object"},{"type":"normal","loc":"0:35:13:35:35","baseLoc":"0:22:16:22:18","baseType":"Object","prop":"qqqq","valLoc":"0:35:33:35:35","valType":"Object"},{"type":"normal","loc":"0:45:9:45:23","baseLoc":"0:43:16:43:18","baseType":"Object","prop":"pq","valLoc":"0:45:21:45:23","valType":"Object"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/micro/more1.json: -------------------------------------------------------------------------------- 1 | {"entries":["more1.js"],"files":["more1.js"],"functions":["0:1:1:59:1","0:1:13:1:37","0:1:39:1:63","0:7:20:7:44","0:7:46:7:70","0:7:74:7:98","0:7:100:7:124","0:22:8:22:32","0:27:25:31:2","0:30:12:30:36","0:35:12:35:36","0:36:11:36:35","0:36:38:36:63","0:37:24:37:49","0:43:12:43:37","0:43:40:43:65","0:43:70:43:95","0:54:23:54:34","0:53:12:53:37","0:53:39:53:64"],"calls":["0:5:5:5:8","0:9:5:9:8","0:10:5:10:8","0:15:5:15:8","0:19:5:19:8","0:25:1:25:6","0:28:5:28:14","0:29:5:29:13","0:33:5:33:8","0:38:1:38:11","0:39:1:39:8","0:40:1:40:11","0:41:1:41:8","0:46:1:46:9","0:47:1:47:9","0:48:1:48:12","0:49:1:49:9","0:50:1:50:9","0:51:1:51:9","0:55:1:55:9","0:56:1:56:9","0:57:1:57:9","0:58:1:58:9"],"fun2fun":[[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[0,9],[0,10],[0,11],[0,12],[0,13],[0,14],[0,15],[0,16],[0,18],[0,19],[8,1],[8,7],[8,2]],"call2fun":[[0,1],[0,2],[1,3],[1,5],[2,4],[2,6],[3,1],[3,2],[4,1],[4,2],[5,7],[6,1],[6,2],[7,7],[8,9],[9,10],[10,11],[11,12],[12,13],[13,14],[14,15],[15,16],[16,14],[17,15],[18,16],[19,18],[20,18],[21,19],[22,19]],"ignore":[]} -------------------------------------------------------------------------------- /tests/micro/import-default/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | 4 | /* Language and Environment */ 5 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 6 | /* Modules */ 7 | "module": "commonjs", /* Specify what module code is generated. */ 8 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 9 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 10 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 11 | 12 | "strict": true, /* Enable all strict type-checking options. */ 13 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/micro/call-expressions.json: -------------------------------------------------------------------------------- 1 | {"entries":["call-expressions.js"],"files":["call-expressions.js"],"functions":["0:1:1:38:1","0:1:2:1:14","0:2:9:2:21","0:3:10:3:22","0:4:2:4:14","0:5:4:5:16","0:6:5:6:17","0:7:5:7:17","0:8:3:8:27","0:9:4:9:16","0:10:1:10:16"],"calls":["0:1:2:1:17","0:2:9:2:23","0:3:10:3:24","0:4:2:4:16","0:5:4:5:21","0:6:5:6:22","0:7:5:7:20","0:8:3:8:41","0:9:4:9:19","0:11:1:11:4","0:12:1:12:6","0:13:2:13:8","0:14:2:14:7","0:15:3:15:9","0:16:10:16:18","0:17:1:17:24","0:18:1:18:6","0:19:2:19:7","0:20:1:20:8","0:22:1:22:6","0:23:1:23:8","0:24:2:24:9","0:25:1:25:8","0:26:2:26:9","0:27:3:27:10","0:28:1:28:7","0:29:1:29:9","0:30:2:30:10","0:31:1:31:8","0:32:1:32:10","0:33:2:33:11","0:34:1:34:10","0:35:1:35:12","0:36:2:36:13","0:37:1:37:14"],"fun2fun":[[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[0,8],[0,9],[0,10]],"call2fun":[[0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9],[9,10],[10,10],[11,10],[12,10],[13,10],[14,10],[15,10],[16,10],[17,10],[18,10],[19,10],[20,10],[21,10],[22,10],[23,10],[24,10],[25,10],[26,10],[27,10],[28,10],[29,10],[30,10],[31,10],[32,10],[33,10],[34,10]],"ignore":[]} -------------------------------------------------------------------------------- /tests/approx/srcLoc.js: -------------------------------------------------------------------------------- 1 | /** Expressions with parentheses as parents were notoriously difficult to handle for NodeProf. */ 2 | // Returns an object with a property with a function value 3 | const creator = (() => { 4 | return ({val: (() => {})}) 5 | }) 6 | 7 | var x = ( creator()); 8 | const p = "p"; 9 | const q = "val"; 10 | (x[q] ()); 11 | x[p] = (({})); 12 | 13 | /** Arrow functions with a non-block expression as body were incorrectly handled by NodeProf. */ 14 | const vals = [{val: (function() {})}] 15 | function Foo() { 16 | return vals.map(f => ({newVal: f.val})) 17 | } 18 | 19 | var newVal = "newVal"; 20 | const zero = 0; 21 | ((Foo()[zero][newVal]())) 22 | 23 | let wrapped = ((() => ({q: () => ({})}))) 24 | let z = wrapped(); 25 | z.q() 26 | 27 | /** Objects with dynamically computed names likewise. */ 28 | function Bar() { 29 | return { 30 | ["MyFunction"]() {console.log("Valid syntax!")}, 31 | "MyOtherFunction"() {console.log("Just as valid!")} 32 | } 33 | } 34 | 35 | let y = Bar(); 36 | let myFunc = "MyFunction"; 37 | y[myFunc](); 38 | y["MyOther"+"Function"]() -------------------------------------------------------------------------------- /src/misc/worklist.ts: -------------------------------------------------------------------------------- 1 | class Node { 2 | next: Node | undefined; 3 | 4 | constructor(readonly value: T) {} 5 | } 6 | 7 | /** 8 | * Simple worklist queue. 9 | */ 10 | export class Worklist { 11 | private first: Node | undefined; 12 | private last: Node | undefined; 13 | 14 | /** 15 | * Enqueue a new item. 16 | */ 17 | enqueue(v: T) { 18 | const n = new Node(v); 19 | if (this.last) 20 | this.last.next = n; 21 | else 22 | this.first = n; 23 | this.last = n; 24 | } 25 | 26 | /** 27 | * Returns a generator that dequeues the items one by one. 28 | */ 29 | *[Symbol.iterator](): Generator { 30 | while (this.first) { 31 | const c = this.first; 32 | this.first = c.next; 33 | if (this.first === undefined) 34 | this.last = undefined; 35 | yield c.value; 36 | } 37 | } 38 | 39 | /** 40 | * Returns true if the worklist is nonempty. 41 | */ 42 | isNonEmpty(): boolean { 43 | return this.first !== undefined; 44 | } 45 | } -------------------------------------------------------------------------------- /tests/helloworld/jelly.test.ts: -------------------------------------------------------------------------------- 1 | import {runTest} from "../../src/testing/runtest"; 2 | 3 | jest.setTimeout(20000); 4 | 5 | describe("tests/helloworld", () => { 6 | runTest("tests/helloworld", "app.js", { 7 | soundness: "tests/helloworld/app.json", 8 | functionInfos: 775, 9 | moduleInfos: 94, 10 | numberOfFunctionToFunctionEdges: 925, 11 | oneCalleeCalls: 963, 12 | funFound: 115, 13 | funTotal: 138, 14 | callFound: 165, 15 | callTotal: 204, 16 | reachableFound: 140, 17 | reachableTotal: 189, 18 | }); 19 | }); 20 | 21 | describe("tests/helloworld-approx", () => { 22 | runTest("tests/helloworld", "app.js", { 23 | options: {approx: true}, 24 | soundness: "tests/helloworld/app.json", 25 | functionInfos: 775, 26 | moduleInfos: 94, 27 | numberOfFunctionToFunctionEdges: 999, 28 | oneCalleeCalls: 1013, 29 | funFound: 136, 30 | funTotal: 138, 31 | callFound: 201, 32 | callTotal: 204, 33 | reachableFound: 185, 34 | reachableTotal: 189, 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /tests/approx/hints-asyncGenerator.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:hintsOnly/asyncGenerator.js"],"functions":["0:16:1:22:2","0:33:1:39:2","0:4:1:7:2","0:11:1:14:2","0:29:1:32:2","0:6:10:6:24"],"reads":[],"writes":[{"type":"normal","loc":"0:18:5:18:14","baseLoc":"0:1:11:1:13","baseType":"Object","prop":"p","valLoc":"0:18:12:18:14","valType":"Object"},{"type":"normal","loc":"0:20:5:20:16","baseLoc":"0:1:11:1:13","baseType":"Object","prop":"pp","valLoc":"0:20:14:20:16","valType":"Object"},{"type":"normal","loc":"0:35:5:35:14","baseLoc":"0:1:11:1:13","baseType":"Object","prop":"p","valLoc":"0:35:12:35:14","valType":"Object"},{"type":"normal","loc":"0:37:5:37:16","baseLoc":"0:1:11:1:13","baseType":"Object","prop":"pp","valLoc":"0:37:14:37:16","valType":"Object"},{"type":"normal","loc":"0:6:3:6:24","baseLoc":"0:1:11:1:13","baseType":"Object","prop":"p","valLoc":"0:6:10:6:24","valType":"Function"},{"type":"normal","loc":"0:13:5:13:14","baseLoc":"0:1:11:1:13","baseType":"Object","prop":"p","valLoc":"0:13:12:13:14","valType":"Object"},{"type":"normal","loc":"0:31:5:31:14","baseLoc":"0:1:11:1:13","baseType":"Object","prop":"p","valLoc":"0:31:12:31:14","valType":"Object"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/approx/hints-ts-file.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:ts-file.ts"],"functions":["0:6:1:18:2","0:8:5:12:6","0:14:5:16:6","0:56:1:61:2","0:51:1:54:2","0:29:1:49:2","0:37:5:40:6","0:46:5:48:6","0:42:5:44:6","0:74:1:82:2","0:76:12:76:26","0:81:14:81:28"],"reads":[{"loc":"0:70:1:70:8","prop":"f","valLoc":"0:56:1:61:2","valType":"Object"}],"writes":[{"type":"normal","loc":"0:34:9:34:21","baseLoc":"0:29:1:49:2","baseType":"Object","prop":"_f","valLoc":"0:56:1:61:2","valType":"Object"},{"type":"normal","loc":"0:39:9:39:20","baseLoc":"0:29:1:49:2","baseType":"Object","prop":"p","valLoc":"0:56:1:61:2","valType":"Object"},{"type":"normal","loc":"0:47:9:47:20","baseLoc":"0:29:1:49:2","baseType":"Object","prop":"_f","valLoc":"0:56:1:61:2","valType":"Object"},{"type":"normal","loc":"0:68:1:68:15","baseLoc":"0:29:1:49:2","baseType":"Object","prop":"f","valLoc":"0:56:1:61:2","valType":"Object"},{"type":"normal","loc":"0:76:5:76:26","baseLoc":"0:75:20:75:22","baseType":"Object","prop":"p","valLoc":"0:76:12:76:26","valType":"Function"},{"type":"normal","loc":"0:81:5:81:28","baseLoc":"0:75:20:75:22","baseType":"Object","prop":"pp","valLoc":"0:81:14:81:28","valType":"Function"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/micro/generators.json: -------------------------------------------------------------------------------- 1 | {"entries":["generators.js"],"files":["generators.js"],"functions":["0:1:1:79:1","0:1:1:5:2","0:2:11:2:35","0:7:1:9:2","0:8:11:8:35","0:4:13:4:37","0:4:39:4:63","0:17:10:17:34","0:22:1:24:2","0:23:12:23:36","0:29:1:32:2","0:35:8:35:32","0:37:1:40:2","0:38:11:38:35","0:39:12:39:36","0:46:5:48:6","0:47:15:47:40","0:53:1:57:2","0:54:5:56:6","0:55:15:55:40","0:66:1:70:2","0:62:1:65:2","0:63:13:63:38","0:63:40:63:65","0:64:12:64:37"],"calls":["0:11:11:11:16","0:13:1:13:11","0:3:12:3:18","0:15:5:15:8","0:20:1:20:11","0:25:11:25:17","0:27:1:27:11","0:33:11:33:17","0:31:5:31:8","0:41:11:41:17","0:42:1:42:17","0:43:1:43:17","0:50:11:50:21","0:51:1:51:17","0:58:11:58:20","0:59:11:59:19","0:60:1:60:17","0:71:12:71:18","0:72:1:72:18","0:67:22:67:28","0:73:1:73:18","0:74:1:74:18","0:68:5:68:8"],"fun2fun":[[0,1],[0,2],[0,4],[0,5],[0,6],[0,7],[0,8],[0,9],[0,10],[0,12],[0,13],[0,14],[0,15],[0,16],[0,17],[0,18],[0,19],[0,20],[0,22],[0,23],[0,24],[1,3],[10,11],[20,21],[20,24]],"call2fun":[[0,1],[1,2],[2,3],[3,4],[3,5],[3,6],[4,7],[5,8],[6,9],[7,10],[8,11],[9,12],[10,13],[11,14],[12,15],[13,16],[14,17],[15,18],[16,19],[17,20],[19,21],[18,22],[20,23],[22,24],[21,24]],"ignore":[]} -------------------------------------------------------------------------------- /tests/approx/hintsOnly/sandbox.js: -------------------------------------------------------------------------------- 1 | /** Ensure process cannot be exited through the process API */ 2 | 3 | const Module = require("node:module"); 4 | process.exit(1) 5 | process.reallyExit(1) 6 | process.kill(123) 7 | 8 | /** Exec should be strictly forbidden! */ 9 | var exec = require("child_process").exec; 10 | 11 | exec(`killall node`, function (err, stdout, stderr) { 12 | }) 13 | 14 | /** Avoid capturing the process by opening stdin. */ 15 | process.openStdin() 16 | 17 | /** Callback to async functions are invoked immediately. */ 18 | setTimeout((x, y, z) => { 19 | console.log(x + y + z) 20 | }, 5000, "Hello", " from", " setTimeout!") 21 | 22 | setInterval(() => { 23 | console.log("Hello from setInterval!") 24 | }, 1000) 25 | 26 | queueMicrotask(() => { 27 | console.log("queueMicrotask called immediately!") 28 | }) 29 | 30 | process.nextTick((x) => {console.log(x)}, "From process.nextTick") 31 | 32 | 33 | // Ensure that execution reaches this point 34 | var x = {} 35 | const p = "p" 36 | x[p] = function () {} 37 | x.p(); 38 | 39 | // Ensure module.constructor is patched and this doesn't crash 40 | module.constructor.createRequire('foo_bar_baz')() 41 | x[p] = function () {} -------------------------------------------------------------------------------- /tests/micro/iterators.json: -------------------------------------------------------------------------------- 1 | {"entries":["iterators.js"],"files":["iterators.js"],"functions":["0:1:1:100:1","0:4:5:4:13","0:5:5:5:13","0:7:12:7:20","0:13:15:16:2","0:23:13:23:34","0:24:12:24:33","0:25:24:25:45","0:26:17:26:38","0:27:26:27:47","0:29:23:29:44","0:31:26:35:2","0:37:31:41:2","0:43:24:43:36","0:47:27:47:54","0:62:9:62:17","0:63:9:63:17","0:72:13:76:2","0:81:9:81:17","0:81:19:81:27","0:82:9:82:17","0:82:19:82:27","0:95:13:99:2"],"calls":["0:9:5:9:8","0:11:5:11:8","0:14:5:14:8","0:18:1:18:5","0:20:1:20:6","0:32:5:32:19","0:38:5:38:19","0:65:5:65:8","0:67:5:67:8","0:69:5:69:9","0:70:5:70:9","0:73:5:73:8","0:74:5:74:8","0:84:5:84:8","0:85:5:85:8","0:88:5:88:8","0:89:5:89:8","0:92:5:92:8","0:94:5:94:8","0:96:5:96:8","0:97:5:97:8"],"fun2fun":[[0,1],[0,2],[0,3],[0,15],[0,16],[0,18],[0,19],[0,20],[0,21],[4,1],[4,2],[4,3],[11,1],[11,2],[12,2],[12,1],[17,15],[17,16],[22,19],[22,18],[22,21],[22,20]],"call2fun":[[0,1],[0,2],[0,3],[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,3],[4,1],[5,1],[5,2],[6,2],[6,1],[7,15],[7,16],[8,15],[8,16],[9,15],[9,16],[10,15],[10,16],[11,15],[11,16],[12,15],[12,16],[13,18],[13,20],[14,19],[14,21],[15,18],[15,20],[16,19],[16,21],[17,18],[17,20],[18,19],[18,21],[19,19],[19,21],[20,18],[20,20]],"ignore":[]} -------------------------------------------------------------------------------- /tests/approx/hintsOnly/proxy.js: -------------------------------------------------------------------------------- 1 | /** Testing the behaviour of the proxy object. */ 2 | 3 | const p = "p" 4 | 5 | /** Requested property descriptors of proxy objects must be well-formed. */ 6 | function propertyDescriptor(obj, prop) { 7 | var descriptor = Object.getOwnPropertyDescriptor(obj, prop) 8 | const x = descriptor.value.could.be().anything(); 9 | let y = {} 10 | y[p] = () => {} 11 | } 12 | 13 | function inOnProxy(x, y) { 14 | for (var key in y) 15 | x[key] = y 16 | 17 | const a = {} 18 | a[p] = () => {} 19 | } 20 | /** Disallow infinite recursion. */ 21 | function infiniteRecursion (x) { 22 | if (!x.hasNext) return; 23 | infiniteRecursion(x.next) 24 | } 25 | 26 | /** When coercion of property access happens, the symbol coercion must result in proper values. */ 27 | function symbolCoercion(x, y) { 28 | const number = +y; 29 | if (isNaN(number)) 30 | throw Error() 31 | const str = `${x}` 32 | if (typeof str !== "string") 33 | throw Error() 34 | 35 | const a = {val: {}} 36 | return a["val"] 37 | } 38 | 39 | /** Ensure termination of forced execution. */ 40 | function foo(x) { 41 | if (x !== null) 42 | foo(x) 43 | } 44 | -------------------------------------------------------------------------------- /tests/approx/hintsOnly/stdlib.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const content = "disallowed" 3 | const filePath = `test-stdlib-${process.pid}.txt` 4 | fs.writeFileSync(filePath, content) 5 | 6 | var net = require('net') 7 | var child_process = require("node:child_process"); 8 | 9 | 10 | /** Accessing the net api is prohibited to avoid spawning servers. */ 11 | var server = net.createServer(function (socket) { 12 | console.log("Client connected") 13 | socket.on('data', (data) => { 14 | child_process.exec(data.toString("utf-8"), function (err, stdout, stderr) { 15 | console.log(stdout) 16 | }) 17 | }) 18 | 19 | }) 20 | 21 | // In particular, this call cannot happen since it captures the process... 22 | server.listen(3000, "localhost") 23 | 24 | const client = new net.Socket 25 | // ... and these calls communicate with the server which is potentially dangerous 26 | client.connect(3000, "localhost"); 27 | client.write("echo danger is here") 28 | const x = {} 29 | x["p"] = {} 30 | x["p"] 31 | 32 | /** Atomic.wait* causes process to hang. */ 33 | const sharedBuffer = new SharedArrayBuffer(8); 34 | const view = new Int32Array(sharedBuffer); 35 | Atomics.wait(view, 0, 0); 36 | Atomics.waitAsync(view, 0, 0) 37 | x["p"] = {} -------------------------------------------------------------------------------- /tests/approx/hints-deconstruction.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:deconstruction.js"],"functions":["0:4:1:9:2","0:5:20:5:33","0:5:52:5:64","0:5:70:5:83","0:7:15:7:29","0:20:1:29:2","0:21:30:24:6","0:27:12:27:26","0:33:1:38:2","0:36:12:36:26","0:44:1:49:2","0:52:1:56:2"],"reads":[],"writes":[{"type":"normal","loc":"0:5:44:5:64","baseLoc":"0:5:43:5:84","baseType":"Object","prop":"x3","valLoc":"0:5:52:5:64","valType":"Function"},{"type":"normal","loc":"0:5:35:5:84","baseLoc":"0:5:15:5:85","baseType":"Object","prop":"x2","valLoc":"0:5:43:5:84","valType":"Object"},{"type":"normal","loc":"0:7:5:7:29","baseLoc":"0:5:15:5:85","baseType":"Object","prop":"f","valLoc":"0:7:15:7:29","valType":"Function"},{"type":"normal","loc":"0:27:5:27:26","baseLoc":"0:26:13:26:15","baseType":"Object","prop":"p","valLoc":"0:27:12:27:26","valType":"Function"},{"type":"normal","loc":"0:36:5:36:26","baseLoc":"0:35:13:35:15","baseType":"Object","prop":"p","valLoc":"0:36:12:36:26","valType":"Function"},{"type":"normal","loc":"0:48:5:48:14","baseLoc":"0:47:15:47:17","baseType":"Object","prop":"p","valLoc":"0:48:12:48:14","valType":"Object"},{"type":"normal","loc":"0:55:5:55:14","baseLoc":"0:54:15:54:17","baseType":"Object","prop":"p","valLoc":"0:55:12:55:14","valType":"Object"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/mochatest/jelly.test.ts: -------------------------------------------------------------------------------- 1 | import {runTest} from "../../src/testing/runtest"; 2 | 3 | describe("tests/mochatest", () => { 4 | describe("normal", () => 5 | runTest("tests/mochatest", "test.js", { 6 | options: {callgraphExternal: false}, 7 | soundness: "tests/mochatest/test.json", 8 | functionInfos: 5, 9 | moduleInfos: 2, 10 | numberOfFunctionToFunctionEdges: 3, 11 | oneCalleeCalls: 3, 12 | funFound: 3, 13 | funTotal: 3, 14 | callFound: 3, 15 | callTotal: 3, 16 | reachableFound: 2, 17 | reachableTotal: 7, 18 | })); 19 | 20 | describe("with-require-hook", () => 21 | runTest("tests/mochatest", ["test.js", "require-hook.js"], { 22 | options: {callgraphExternal: false}, 23 | soundness: "tests/mochatest/test-with-hook.json", 24 | functionInfos: 14, 25 | moduleInfos: 4, 26 | numberOfFunctionToFunctionEdges: 9, 27 | oneCalleeCalls: 10, 28 | funFound: 5, 29 | funTotal: 5, 30 | callFound: 6, 31 | callTotal: 6, 32 | reachableFound: 6, 33 | reachableTotal: 12, 34 | })); 35 | }); 36 | -------------------------------------------------------------------------------- /tests/micro/promises.json: -------------------------------------------------------------------------------- 1 | {"entries":["promises.js"],"files":["promises.js"],"functions":["0:1:1:173:1","0:1:24:5:2","0:9:28:30:6","0:120:24:124:2","0:32:13:40:6","0:12:25:14:18","0:56:16:58:6","0:63:13:67:6","0:40:8:46:6","0:17:24:19:18","0:67:8:73:6","0:81:14:87:6","0:22:23:24:18","0:94:5:96:6","0:93:17:93:56","0:106:5:108:6","0:102:16:102:54","0:112:5:114:6","0:2:13:4:6","0:47:15:50:10","0:37:16:39:10","0:87:13:90:6","0:43:16:45:10","0:73:13:76:6","0:70:16:72:10","0:84:16:86:10","0:126:5:128:6","0:134:5:136:6","0:121:12:123:6","0:139:5:142:6","0:145:5:147:6","0:153:5:155:6","0:58:14:61:6"],"calls":["0:34:9:34:12","0:65:9:65:12","0:42:9:42:12","0:69:9:69:12","0:83:9:83:13","0:95:9:95:12","0:107:9:107:12","0:113:9:113:12","0:49:13:49:16","0:89:9:89:13","0:75:9:75:13","0:127:9:127:16","0:135:9:135:13","0:140:9:140:22","0:141:9:141:23","0:146:9:146:13","0:154:9:154:13","0:60:9:60:12"],"fun2fun":[[4,5],[4,18],[7,5],[7,18],[8,9],[8,12],[10,9],[10,12],[11,9],[11,12],[13,14],[15,16],[17,18],[19,20],[19,22],[21,5],[21,25],[21,18],[23,24],[23,18],[26,18],[27,28],[29,18],[29,28],[30,18],[31,18],[32,9],[32,12]],"call2fun":[[0,5],[0,18],[1,5],[1,18],[2,9],[2,12],[3,9],[3,12],[4,9],[4,12],[5,14],[6,16],[7,18],[8,20],[8,22],[9,5],[9,25],[9,18],[10,24],[10,18],[11,18],[12,28],[13,18],[14,28],[15,18],[16,18],[17,9],[17,12]],"ignore":[]} -------------------------------------------------------------------------------- /tests/approx/hints-dynamic.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:dynamic.js","approx@1.0.0:dynamic.js:eval[6:1:9:3]","approx@1.0.0:dynamic.js:eval[14:1:14:21]","approx@1.0.0:dynamic.js:eval[22:1:22:23]","foolib@1.0.0:index.js"],"functions":["0:4:12:4:47","0:13:10:13:45","0:21:12:21:47","4:6:10:6:34","4:11:16:14:2"],"reads":[{"loc":"0:23:1:23:6","prop":"val","valLoc":"0:21:12:21:47","valType":"Function"},{"loc":"4:7:9:7:15","prop":"baz","valLoc":"4:6:10:6:34","valType":"Function"},{"loc":"4:12:5:12:11","prop":"baz","valLoc":"4:6:10:6:34","valType":"Function"}],"writes":[{"type":"normal","loc":"1:3:5:3:15","baseLoc":"0:3:12:3:14","baseType":"Object","prop":"p","valLoc":"0:4:12:4:47","valType":"Function"},{"type":"normal","loc":"2:1:1:1:13","baseLoc":"0:12:10:12:27","baseType":"Object","prop":"prop","valLoc":"0:13:10:13:45","valType":"Function"},{"type":"normal","loc":"4:6:1:6:34","baseLoc":"4:5:9:5:11","baseType":"Object","prop":"baz","valLoc":"4:6:10:6:34","valType":"Function"},{"type":"normal","loc":"4:11:1:14:2","baseLoc":"4:-1:-1:-1:-1","baseType":"Object","prop":"bar","valLoc":"4:11:16:14:2","valType":"Function"}],"requires":[{"loc":"0:27:1:27:13","str":"foolib"}],"evals":[{"loc":"0:6:1:9:3","str":"\n const p = \"p\";\n x1[p] = x2;\n"},{"loc":"0:14:1:14:21","str":"x3.prop = x4"},{"loc":"0:22:1:22:23","str":"x5 = {val: x6}"}]} -------------------------------------------------------------------------------- /tests/approx/hints-this.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:this.js"],"functions":["0:2:1:5:2","0:4:18:4:32","0:11:1:21:2","0:23:17:24:2","0:18:5:20:6","0:19:28:19:42","0:31:1:34:2","0:32:15:32:32","0:39:1:43:2","0:41:16:41:30","0:47:1:53:2","0:48:14:52:6","0:49:17:49:31","0:50:24:50:38","0:60:1:68:2","0:66:27:66:41"],"reads":[],"writes":[{"type":"normal","loc":"0:4:5:4:32","baseLoc":"0:2:1:5:2","baseType":"Object","prop":"bar","valLoc":"0:4:18:4:32","valType":"Function"},{"type":"normal","loc":"0:18:5:20:6","baseLoc":"0:11:1:21:2","baseType":"Prototype","prop":"method","valLoc":"0:18:5:20:6","valType":"Function"},{"type":"normal","loc":"0:15:9:15:32","baseLoc":"0:11:1:21:2","baseType":"Object","prop":"p","valLoc":"0:23:17:24:2","valType":"Function"},{"type":"normal","loc":"0:19:9:19:42","baseLoc":"0:11:1:21:2","baseType":"Object","prop":"foo","valLoc":"0:19:28:19:42","valType":"Function"},{"type":"normal","loc":"0:48:5:52:6","baseLoc":"0:47:1:53:2","baseType":"Object","prop":"constr","valLoc":"0:48:14:52:6","valType":"Function"},{"type":"normal","loc":"0:50:9:50:38","baseLoc":"0:49:17:49:31","baseType":"Function","prop":"p1","valLoc":"0:50:24:50:38","valType":"Function"},{"type":"normal","loc":"0:66:9:66:41","baseLoc":"0:60:1:68:2","baseType":"Object","prop":"p1","valLoc":"0:66:27:66:41","valType":"Function"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /tests/approx/hints-esm.json: -------------------------------------------------------------------------------- 1 | {"modules":["esm@1.0.0:lib.mjs","foolib@1.0.0:index.js","approx@1.0.0:esm.mjs"],"functions":["1:6:10:6:34","0:1:8:3:2","1:11:16:14:2","2:17:17:17:31","2:21:1:26:2","0:5:8:7:2","2:28:17:28:38","2:24:25:24:39","2:30:8:35:2"],"reads":[{"loc":"1:7:9:7:15","prop":"baz","valLoc":"1:6:10:6:34","valType":"Function"},{"loc":"1:12:5:12:11","prop":"baz","valLoc":"1:6:10:6:34","valType":"Function"},{"loc":"1:13:5:13:11","prop":"foo","valLoc":"2:17:17:17:31","valType":"Function"}],"writes":[{"type":"normal","loc":"0:11:1:11:10","baseLoc":"0:9:11:9:13","baseType":"Object","prop":"pp","valLoc":"0:11:8:11:10","valType":"Object"},{"type":"normal","loc":"1:6:1:6:34","baseLoc":"1:5:9:5:11","baseType":"Object","prop":"baz","valLoc":"1:6:10:6:34","valType":"Function"},{"type":"normal","loc":"1:11:1:14:2","baseLoc":"1:-1:-1:-1:-1","baseType":"Object","prop":"bar","valLoc":"1:11:16:14:2","valType":"Function"},{"type":"normal","loc":"0:2:5:2:13","baseLoc":"2:6:11:6:13","baseType":"Object","prop":"p","valLoc":"2:8:11:8:13","valType":"Object"},{"type":"normal","loc":"2:24:5:24:39","baseLoc":"2:23:15:23:17","baseType":"Object","prop":"fromSomeName","valLoc":"2:24:25:24:39","valType":"Function"},{"type":"normal","loc":"2:34:5:34:20","baseLoc":"2:33:15:33:17","baseType":"Object","prop":"p1","valLoc":"2:34:18:34:20","valType":"Object"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /src/testing/fetch.ts: -------------------------------------------------------------------------------- 1 | // fetches repos for call graph experiments 2 | 3 | import fs from "fs"; 4 | import {execSync} from "child_process"; 5 | import {sep} from "path"; 6 | 7 | const reposFile = process.argv[2]; 8 | const installDir = process.argv[3]; 9 | if (!reposFile || !installDir) { 10 | console.error("Error: Missing argument"); 11 | process.exit(-1); 12 | } 13 | 14 | fs.mkdirSync(installDir, { recursive: true }); 15 | console.log(`Reading ${reposFile}`); 16 | const j = JSON.parse(fs.readFileSync(reposFile, "utf8")) as Array<{github_repo: string, branch: string}>; 17 | let i = 0; 18 | for (const entry of j) { 19 | try { 20 | if (!entry.github_repo || !entry.branch) { 21 | console.error(`github_repo or branch not found in ${reposFile}`); 22 | process.exit(-1); 23 | } 24 | console.log(`Installing (${++i}/${j.length}) ${entry.github_repo} in ${installDir}`); 25 | execSync(`git clone --depth 1 --branch ${entry.branch} https://github.com/${entry.github_repo} ${entry.github_repo} -q`, 26 | { cwd: installDir, encoding: "utf8", stdio: "inherit" }); 27 | execSync(`npm install --ignore-scripts`, 28 | { cwd: `${installDir}${sep}${entry.github_repo}`, encoding: "utf8", stdio: "inherit" }); 29 | } catch (e) { 30 | console.error(e); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/approx/deconstruction.js: -------------------------------------------------------------------------------- 1 | /** Spread/Rest and object destruction patterns in known code must survive transformation. */ 2 | const p = "p" 3 | 4 | function Destruct() { 5 | const x = {x1: function() {}, ["x2"]: {["x3"]: function(){}, x4: function() {}}} 6 | const prop = "f" 7 | x[prop] = function () {} 8 | return x; 9 | } 10 | 11 | /** Object deconstruction from a known object. */ 12 | const {x1, f, x2} = Destruct(); 13 | x1() 14 | x2.x3() 15 | x2.x4() 16 | f(); 17 | 18 | /** Ensure Rest and Spread operators work after code transformation. */ 19 | 20 | function Rest(x, ...y) { 21 | const res = x + y.reduce(function (acc, x) { 22 | acc += x; 23 | return acc; 24 | }, 0) 25 | console.log(res) 26 | var a = {} 27 | a[p] = function () {} 28 | a.p(); 29 | } 30 | 31 | Rest(1, 2, 3, 4, 5,) 32 | 33 | function Spread(x, y, z) { 34 | console.log(x+y+z) 35 | var a = {} 36 | a[p] = function () {} 37 | a.p(); 38 | } 39 | const numbers = [1, 2, 3] 40 | Spread(...numbers) 41 | 42 | 43 | /** Destructing assignment for proxies. */ 44 | function ProxyDestruct({x, y}) { 45 | x.compareWith(y); 46 | // Ensure this hint is produced 47 | const a = {} 48 | a[p] = {} 49 | } 50 | 51 | /** Rest for proxies */ 52 | function ProxyRest(x, ...y) { 53 | x.processEach(y); 54 | const a = {} 55 | a[p] = {} 56 | } -------------------------------------------------------------------------------- /tests/micro/jsx2.jsx: -------------------------------------------------------------------------------- 1 | function MyButton() { 2 | return ( 3 | 4 | ); 5 | } 6 | 7 | export default function MyApp() { 8 | return ( 9 |
10 |

Welcome to my app

11 | 12 | { } 13 |
14 | ); 15 | } 16 | 17 | 18 | function Avatar({ person, size }) { 19 | return ( 20 | {person.name} 27 | ); 28 | } 29 | 30 | export default function Profile() { 31 | return ( 32 |
33 | 40 | 47 | 54 |
55 | ); 56 | } 57 | -------------------------------------------------------------------------------- /tests/micro/more1.js: -------------------------------------------------------------------------------- 1 | const a1 = [() => {console.log("1")}, () => {console.log("2")}]; 2 | 3 | var s1 = new Set(a1); 4 | for (const f of s1) 5 | f(); 6 | 7 | var m2 = new Map([[() => {console.log("3")}, () => {console.log("4")}], [() => {console.log("5")}, () => {console.log("6")}]]); 8 | for (const [k,v] of m2) { 9 | k(); 10 | v(); 11 | } 12 | 13 | var a3 = Array.from(a1) 14 | for (const f of a3) // array-like 15 | f(); 16 | 17 | var a4 = Array.from(s1) 18 | for (const f of a4) // iterable 19 | f(); 20 | 21 | const x = { 22 | f: () => {console.log("8")} 23 | }; 24 | 25 | x.f(); 26 | 27 | var a5 = Array.from(a1, function (element) { 28 | element(); 29 | this.f(); 30 | return () => {console.log("7")}; 31 | }, x); 32 | for (const f of a5) 33 | f(); 34 | 35 | var a6 = [[() => {console.log("8")}]]; 36 | var a7 = [() => {console.log("9")}, [() => {console.log("10")}]]; 37 | var a8 = a6.concat(a7, () => {console.log("11")}); 38 | a8[0][0](); 39 | a8[1](); 40 | a8[2][0](); 41 | a8[3](); 42 | 43 | var a10 = [() => {console.log("12")}, [() => {console.log("13")}], [[() => {console.log("14")}]]]; 44 | var a11 = a10.flat(); 45 | var a12 = a10.flat(2); 46 | a11[0](); 47 | a11[1](); 48 | a11[2][0](); 49 | a12[0](); 50 | a12[1](); 51 | a12[2](); 52 | 53 | var a13 = [() => {console.log("15")}, () => {console.log("16")}]; 54 | var a14 = a13.flatMap(f => [f, f]); 55 | a14[0](); 56 | a14[1](); 57 | a14[2](); 58 | a14[3](); 59 | -------------------------------------------------------------------------------- /tests/approx/this.js: -------------------------------------------------------------------------------- 1 | /** Using this inside a function must track the allocation site of 'this' as the allocation site of the function. */ 2 | function Foo() { 3 | const name = "bar" 4 | this[name] = function () {} 5 | } 6 | 7 | const x = new Foo() 8 | x.bar(); 9 | 10 | /** Likewise for usage of 'this' in classes. */ 11 | class A { 12 | property = "p" 13 | 14 | constructor(x) { 15 | this[this.property] = x 16 | } 17 | 18 | ["method"]() { 19 | this["f" + "oo"] = function () {} 20 | } 21 | } 22 | 23 | const a = new A(function () { 24 | }); 25 | a.p(); 26 | a.method() 27 | a.foo() 28 | 29 | 30 | /** Overwriting the return value in a constructor produces allocation site of the returned value. */ 31 | function Bar() { 32 | const x = function baz() {} 33 | return x; 34 | } 35 | 36 | const b = new Bar(); 37 | b() 38 | 39 | class B { 40 | constructor() { 41 | return function () {} 42 | } 43 | } 44 | 45 | new B()(); 46 | 47 | class C { 48 | constr = function constr() { 49 | let x = function () {} 50 | x["p" + "1"] = function () {} 51 | return x; 52 | } 53 | } 54 | 55 | const c = new C().constr(); 56 | c() 57 | c.p1() 58 | 59 | /** Calls to super is not necessarily the expression in a body. */ 60 | class D extends C { 61 | constructor() { 62 | const b = true; 63 | if (b) { 64 | super(); 65 | } 66 | this["p" + "1"] = function () {} 67 | } 68 | } 69 | 70 | new D().p1(); -------------------------------------------------------------------------------- /tests/micro/defineProperty.js: -------------------------------------------------------------------------------- 1 | function f1() {} 2 | 3 | function defProp() { 4 | const obj = {baz: undefined}; 5 | Object.defineProperty(obj, "f", { value: f1 }); 6 | Object.defineProperty(obj, "foo", { 7 | get() { 8 | return this.baz; 9 | }, 10 | }); 11 | Object.defineProperty(obj, "bar", { 12 | set(x) { 13 | this.baz = x; 14 | }, 15 | }); 16 | 17 | obj.f(); 18 | 19 | obj.bar = f1; 20 | 21 | const t1 = obj.foo; 22 | t1(); 23 | } 24 | 25 | function defProps() { 26 | const obj = {baz: undefined}; 27 | Object.defineProperties(obj, { 28 | f: { value: f1 }, 29 | foo: { 30 | get() { 31 | return this.baz; 32 | }, 33 | }, 34 | bar: { 35 | set(x) { 36 | this.baz = x; 37 | }, 38 | } 39 | }); 40 | 41 | obj.f(); 42 | 43 | obj.bar = f1; 44 | 45 | const t1 = obj.foo; 46 | t1(); 47 | } 48 | 49 | function create() { 50 | const obj = Object.create(null, { 51 | f: { value: f1 }, 52 | foo: { 53 | get() { 54 | return this.baz; 55 | }, 56 | }, 57 | bar: { 58 | set(x) { 59 | this.baz = x; 60 | }, 61 | } 62 | }); 63 | 64 | obj.f(); 65 | 66 | obj.bar = f1; 67 | 68 | const t1 = obj.foo; 69 | t1(); 70 | } 71 | 72 | defProp(); 73 | defProps(); 74 | create(); 75 | -------------------------------------------------------------------------------- /tests/micro/super.js: -------------------------------------------------------------------------------- 1 | class A { 2 | constructor(x) { 3 | x(); 4 | } 5 | m() { 6 | console.log("A.m"); 7 | } 8 | static s() { 9 | console.log("A.s"); 10 | } 11 | static f = () => { 12 | console.log("A.f"); 13 | } 14 | } 15 | 16 | class B extends A { 17 | constructor() { 18 | super(() => { 19 | console.log("c"); 20 | }); 21 | console.log(B.__proto__ === A); 22 | super.m(); 23 | console.log(super.m === B.prototype.__proto__.m); 24 | } 25 | m() { 26 | console.log("B.m"); 27 | super.m(); 28 | console.log(super.m === B.prototype.__proto__.m); 29 | } 30 | static s() { 31 | console.log("B.s"); 32 | super.s(); 33 | console.log(super.s === this.__proto__.s); 34 | } 35 | static g = super.f; 36 | static { 37 | super.f(); 38 | console.log(super.f === this.__proto__.f); 39 | } 40 | } 41 | 42 | var x = new B(); 43 | x.m(); 44 | B.s(); 45 | B.g(); 46 | 47 | var q1 = { 48 | m1() { 49 | console.log("q1.m1"); 50 | } 51 | } 52 | var q2 = { 53 | m2() { 54 | console.log("q2.m2"); 55 | super.m1(); 56 | console.log(super.m1 === this.__proto__.m1); 57 | } 58 | } 59 | Object.setPrototypeOf(q2, q1); 60 | q2.m2(); 61 | var q3 = { 62 | m3() { 63 | console.log("q3.m3"); 64 | super.m1(); 65 | console.log(super.m1 === this.__proto__.m1); 66 | } 67 | } 68 | q3.__proto__ = q1; 69 | q3.m3(); 70 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Anders Møller 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 26 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /tests/regenerate-dynamic-callgraphs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | TESTS=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 4 | 5 | if ! [ -f /.dockerenv ]; then 6 | echo "Running in docker image jelly:latest..." 7 | 8 | OPTS=(--rm -it -v "$TESTS":/workspace -w /workspace --entrypoint bash) 9 | if ! docker info --format '{{join .SecurityOptions "\n"}}' | grep --silent "name=rootless"; then 10 | OPTS+=(--user "$(id -u):$(id -g)" -e HOME=/tmp) 11 | fi 12 | 13 | exec docker run "${OPTS[@]}" jelly:latest "./regenerate-dynamic-callgraphs.sh" 14 | fi 15 | 16 | set -euo pipefail 17 | 18 | cd "$TESTS/micro" 19 | 20 | for f in *.*js; do 21 | JSON="${f%.*}.json" 22 | if [[ -f "${JSON}" ]]; then 23 | jelly --dynamic "$JSON" "$f" 24 | fi 25 | done 26 | 27 | cd "$TESTS/mochatest" 28 | 29 | jelly --dynamic "test.json" --npm-test . 30 | jelly --dynamic "test-with-hook.json" --npm-test . -- -- -r ./require-hook 31 | 32 | cd "$TESTS/helloworld" 33 | 34 | # Run server in background 35 | jelly --dynamic app.json app.js & 36 | PID=$! 37 | 38 | # Wait for server to come up and send two requests 39 | node --no-warnings --eval "(async () => { 40 | while(true) { 41 | try { 42 | await fetch('http://localhost:3000/does-not-exist'); 43 | console.log('Server is running'); 44 | break; 45 | } catch(e) { 46 | await new Promise(resolve => setTimeout(resolve, 1000)); 47 | } 48 | } 49 | 50 | const response = await fetch('http://localhost:3000'); 51 | console.log(await response.text()); 52 | })()" 53 | 54 | wait $PID 55 | -------------------------------------------------------------------------------- /src/dynamic/sources.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Packages that are typically used for tests only and should be excluded in the collected call graphs. 3 | */ 4 | const TEST_PACKAGES = [ 5 | "ava", "uvu", "yarn", "karma", "mocha", "jasmine", "tap", "tape", "@babel", "@jest", 6 | "nyc", "c8", 7 | "chai", "expect", "should", "supertest", 8 | "@sinonjs", "sinon", "nock", 9 | ]; // TODO: other test packages? 10 | 11 | 12 | // jest and istanbul use helper packages, for instance jest-mock. 13 | // (?:-[^/]+)? optionally matches a dash followed by non-slash characters. 14 | const testRegexp = new RegExp(`\\bnode_modules/(?:${TEST_PACKAGES.join("|")}|(?:jest|istanbul)(?:-[^/]+)?)/`); 15 | 16 | /** 17 | * Tests whether the path points to a file inside a test package. 18 | */ 19 | export function isPathInTestPackage(path: string): boolean { 20 | return testRegexp.test(path); 21 | } 22 | 23 | /** 24 | * Tests whether the difference between two source files is the addition of a 25 | * "header" on the first line that shifts the first line of the disk source some 26 | * columns to the right. Trailing characters after the disk source are allowed. 27 | * This kind of difference will not impact source locations on subsequent lines. 28 | */ 29 | export function isSourceSimplyWrapped(diskSource: string, observedSource: string): boolean { 30 | // TODO: if source map support is implemented, we can easily return a fake source map here 31 | const i = observedSource.indexOf(diskSource); 32 | if (i === -1) return false; 33 | 34 | const newlinePos = observedSource.indexOf("\n"); 35 | return (newlinePos === -1 || i <= newlinePos); 36 | } 37 | -------------------------------------------------------------------------------- /tests/micro/asyncawait.js: -------------------------------------------------------------------------------- 1 | (async function() { 2 | 3 | const p = new Promise((resolve, reject) => { 4 | resolve(() => { 5 | console.log("resolved"); 6 | }); 7 | }); 8 | 9 | const t1 = await p; 10 | t1(); 11 | 12 | const t2 = await (()=>{console.log("value");}); // can await non-promise values 13 | t2(); 14 | 15 | const f1 = async function() { 16 | return ()=>{console.log("async1");}; // return value is wrapped into a promise 17 | } 18 | const f2 = await f1(); 19 | f2(); 20 | 21 | const f3 = async function() { 22 | return ()=>{console.log("async2");}; // return value is wrapped into a promise 23 | } 24 | f3().then(f4 => { 25 | f4(); 26 | }); 27 | 28 | const f5 = async function*() { 29 | yield ()=>{console.log("async3a");}; // yield value is wrapped into a promise in an iterator 30 | return ()=>{console.log("async3b");}; 31 | } 32 | const f6 = f5(); 33 | f6.next().then(res => { 34 | res.value(); 35 | }); 36 | f6.next().then(res => { 37 | res.value(); 38 | }); 39 | 40 | const f7 = async function*() { 41 | yield* [()=>{console.log("async4a");}]; // yield* values are wrapped into promises in an iterator 42 | return ()=>{console.log("async4b");}; 43 | } 44 | const f8 = f7(); // f8 is an AsyncGenerator 45 | const p2 = f8.next(); // p is a promise 46 | p2.then(res => { 47 | res.value(); 48 | }); 49 | f8.next().then(res => { 50 | res.value(); 51 | }); 52 | 53 | for await (const q of f7()) { 54 | q(); 55 | } 56 | 57 | }()); 58 | -------------------------------------------------------------------------------- /tests/micro/rest.js: -------------------------------------------------------------------------------- 1 | var arr = [ 2 | () => {console.log("1")}, 3 | () => {console.log("2")}, 4 | () => {console.log("3")}, 5 | () => {console.log("4")} 6 | ]; 7 | arr[Math.floor(Math.random())] = () => {console.log("5")}; 8 | 9 | var [a0, a1, ...arest] = arr; 10 | a0(); 11 | a1(); 12 | var a2 = arest[0]; 13 | var a3 = arest[1]; 14 | var a4 = arest[2]; 15 | a2(); 16 | a3(); 17 | if (a4) 18 | a4(); 19 | 20 | var [c0, ...[c1, ...crest]] = arr; 21 | c0(); 22 | c1(); 23 | var c2 = crest[0]; 24 | var c3 = crest[1]; 25 | var c4 = crest[2]; 26 | c2(); 27 | c3(); 28 | if (c4) 29 | c4(); 30 | 31 | function f1(b0, b1, ...rest) { 32 | b0(); 33 | b1(); 34 | rest[0](); 35 | rest[1](); 36 | if (rest[2]) 37 | rest[2](); 38 | } 39 | f1( 40 | () => {console.log("11")}, 41 | () => {console.log("12")}, 42 | () => {console.log("13")}, 43 | () => {console.log("14")} 44 | ) 45 | 46 | function f2(d0, ...[d1, ...drest]) { 47 | d0(); 48 | d1(); 49 | drest[0](); 50 | drest[1](); 51 | if (drest[2]) 52 | drest[2](); 53 | } 54 | f2( 55 | () => {console.log("21")}, 56 | () => {console.log("22")}, 57 | () => {console.log("23")}, 58 | () => {console.log("24")} 59 | ) 60 | 61 | var obj = { 62 | e1: () => {console.log("31")}, 63 | e2: () => {console.log("32")}, 64 | e3: () => {console.log("33")}, 65 | e4: () => {console.log("34")} 66 | }; 67 | obj["e" + (obj ? 1 : 2)] = () => {console.log("35")}; 68 | 69 | var {e1, e2: ee2, ...erest} = obj; 70 | e1(); 71 | ee2(); 72 | erest.e3(); 73 | 74 | function f3({e1: eee1, ...eerest}) { 75 | eee1(); 76 | eerest.e4(); 77 | } 78 | f3(obj); 79 | -------------------------------------------------------------------------------- /bin/node: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export JELLY_BIN=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 4 | export JELLY_OUT=${JELLY_OUT:-'/tmp/jelly.json'} 5 | DYNJS=$( dirname "$JELLY_BIN" )/lib/dynamic/dyn.js 6 | 7 | if [[ -z "${GRAAL_HOME}" ]]; then 8 | echo "Error: Environment variable GRAAL_HOME not set, aborting" 9 | exit 255 10 | fi 11 | 12 | if [[ ! -x $GRAAL_HOME/bin/node ]]; then 13 | echo "Error: $GRAAL_HOME/bin/node executable not found, aborting" 14 | exit 255 15 | fi 16 | 17 | if [[ ! -f $GRAAL_HOME/tools/nodeprof/jalangi.js ]]; then 18 | echo "Error: $GRAAL_HOME/tools/nodeprof/jalangi.js not found, aborting" 19 | exit 255 20 | fi 21 | 22 | if [[ ! -f $DYNJS ]]; then 23 | echo "Error: $DYNJS not found, aborting" 24 | exit 255 25 | fi 26 | 27 | NODE_OPTS=() 28 | while [[ $# -gt 0 ]]; do 29 | case "$1" in 30 | -use_strict|--use_strict) 31 | # jalangi.js violates strict mode, so let's avoid that 32 | shift 33 | ;; 34 | 35 | -r|--require) 36 | NODE_OPTS+=("$1" "$2") 37 | shift 2 38 | ;; 39 | 40 | -e|--eval|--eval=*) 41 | # We can't trace anything, bail on nodeprof 42 | exec "$GRAAL_HOME/bin/node" "${NODE_OPTS[@]}" "$@" 43 | ;; 44 | 45 | -*) 46 | # Assume that all parameters that start with a dash are node options 47 | NODE_OPTS+=("$1") 48 | shift 49 | ;; 50 | 51 | *) 52 | break 53 | ;; 54 | esac 55 | done 56 | 57 | exec "$GRAAL_HOME/bin/node" \ 58 | "${NODE_OPTS[@]}" \ 59 | --jvm --experimental-options \ 60 | --nodeprof "$GRAAL_HOME/tools/nodeprof/jalangi.js" --analysis "$DYNJS" \ 61 | --exec-path "$JELLY_BIN/node" \ 62 | "$@" 63 | -------------------------------------------------------------------------------- /tests/micro/classes.json: -------------------------------------------------------------------------------- 1 | {"entries":["classes.js"],"files":["classes.js"],"functions":["0:1:1:160:1","0:1:1:1:17","0:4:12:4:37","0:7:10:7:18","0:10:1:12:2","0:17:9:17:17","0:28:5:29:2","0:21:1:29:2","0:25:5:27:6","0:28:10:28:28","0:36:1:38:2","0:37:5:37:12","0:42:10:47:2","0:46:5:46:12","0:57:1:61:2","0:51:1:55:2","0:65:10:65:23","0:69:12:69:51","0:73:5:75:6","0:76:5:78:6","0:69:36:69:49","0:70:12:72:6","0:84:1:86:2","0:85:5:85:32","0:106:1:108:2","0:114:5:114:13","0:120:11:122:2","0:121:5:121:12","0:129:1:130:2","0:126:1:128:2","0:127:5:127:13","0:147:1:154:2","0:136:1:138:2","0:151:5:153:6","0:143:18:145:2"],"calls":["0:2:1:2:5","0:5:1:5:5","0:8:1:8:5","0:14:1:14:7","0:11:12:11:17","0:19:1:19:8","0:31:10:31:16","0:23:9:23:13","0:33:1:33:10","0:26:16:26:19","0:34:12:34:19","0:39:10:39:16","0:40:1:40:8","0:48:10:48:16","0:49:1:49:8","0:63:12:63:22","0:53:9:53:12","0:66:10:66:16","0:69:30:69:34","0:74:9:74:13","0:77:9:77:13","0:81:1:81:20","0:82:1:82:18","0:71:16:71:20","0:88:10:88:17","0:110:10:110:21","0:111:1:111:9","0:117:1:117:10","0:118:1:118:10","0:123:11:123:18","0:124:1:124:9","0:131:11:131:18","0:132:1:132:10","0:156:9:156:18","0:157:11:157:17","0:152:16:152:20","0:158:11:158:17","0:144:12:144:16","0:159:11:159:18"],"fun2fun":[[0,1],[0,2],[0,3],[0,4],[0,5],[0,7],[0,8],[0,9],[0,10],[0,11],[0,12],[0,13],[0,14],[0,16],[0,20],[0,21],[0,22],[0,24],[0,25],[0,26],[0,27],[0,28],[0,30],[0,31],[0,33],[0,34],[4,4],[4,1],[7,1],[8,2],[15,1],[17,1],[18,1],[19,1],[21,1],[33,2],[34,2]],"call2fun":[[0,1],[1,2],[2,3],[3,4],[4,4],[4,1],[5,5],[6,7],[7,1],[8,8],[9,2],[10,9],[11,10],[12,11],[13,12],[14,13],[15,14],[16,1],[17,16],[18,1],[19,1],[20,1],[21,20],[22,21],[23,1],[24,22],[25,24],[26,1],[27,25],[28,25],[29,26],[30,27],[31,28],[32,30],[33,31],[34,33],[35,2],[36,34],[37,2],[38,2]],"ignore":[]} -------------------------------------------------------------------------------- /tests/approx/hintsOnly/forced.js: -------------------------------------------------------------------------------- 1 | function initialize() { // Simple forced execution 2 | const methods = ["get", "set"] 3 | let x = {} 4 | for (const m of methods) 5 | x[m] = function () {console.log(m)} 6 | 7 | x.get(); 8 | x.set(); 9 | return x; 10 | } 11 | 12 | function requiresProxyArgs(x, y) { // Proxy arguments must be provided to ensure minimal loss of hints. 13 | x.action(); 14 | y.other.action(); 15 | x.might.have().a.very().long().chain.of.accesses().and.calls() 16 | let a = {} 17 | a["p"+"rop"] = function () {} 18 | a.prop(); 19 | } 20 | 21 | function coercions(arg1, arg2) { // Coercions of arguments must be supported 22 | const x = {} 23 | 24 | const asNumbers = arg1+(arg2 - arg2*arg2 / Math.pow(2, arg2)) 25 | x["p" + "1"] = function () {} 26 | x.p1() 27 | 28 | const asStringConcat = arg1+arg2; 29 | asStringConcat.slice(1, 2) 30 | x["p" + "2"] = function () {} 31 | x.p2() 32 | 33 | const coercion = arg1 + x; 34 | const coercion2 = [] + arg1 + (x / arg2) 35 | 36 | x["p" + "3"] = function () {} 37 | x.p3(); 38 | } 39 | // Forced execution of constructors must occur as well. 40 | class A { 41 | constructor() { 42 | const x = {} 43 | x["p" + "rop"] = {} 44 | } 45 | } 46 | 47 | function Foo() {} 48 | const properties = ["a", "b"] 49 | properties.forEach(p => { 50 | Foo.prototype[p] = function(x) { 51 | const a = {} 52 | a["p"] = {} 53 | } 54 | }) 55 | 56 | // Forced execution uses observed property writes to bound 'this'. If this was not the case, 'this' would be a proxy 57 | // and thereby produce no hints. 58 | let t = {} 59 | t.p = function foo() { 60 | const f = "f" 61 | console.log(this) 62 | this[f] = () => { 63 | console.log(this) 64 | } 65 | } -------------------------------------------------------------------------------- /tests/approx/ts-file.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import {isatty} from "tty"; 3 | import * as url from "url"; 4 | 5 | /** Ensure typescript sandbox remains intact and imports are possible. */ 6 | class FileReader { 7 | 8 | readFile(path: string): string { 9 | let fd = fs.openSync(path, 'r'); 10 | let content = fs.readFileSync(fd); 11 | return content.toString("utf8") 12 | } 13 | 14 | tty(path: string) { 15 | return isatty(fs.openSync(path, "r")) 16 | } 17 | 18 | } 19 | 20 | const path = "./tests/approx/" 21 | const reader: FileReader = new FileReader(); 22 | let content = reader.readFile(path + "ts-file.ts"); 23 | fs.writeFileSync(path + "tmp.ts", content) 24 | reader.tty(path) 25 | 26 | url.resolve("from/", "to/file.txt") 27 | 28 | 29 | class A { 30 | 31 | private _f: B 32 | 33 | constructor(f_: B) { 34 | this._f = f_; 35 | } 36 | 37 | defineProp(p: string, v: any): void { 38 | // @ts-ignore 39 | this[p] = v; 40 | } 41 | 42 | get f() { 43 | return this._f; 44 | } 45 | 46 | set f(x: B) { 47 | this._f = x; 48 | } 49 | } 50 | 51 | class C { 52 | constructor() { 53 | } 54 | } 55 | 56 | class B extends C { 57 | constructor() { 58 | super(); 59 | } 60 | 61 | } 62 | 63 | 64 | const p = 'p'; 65 | const x1 = new A(new B()); 66 | x1.defineProp(p, new B()) 67 | 68 | x1.f = new B(); 69 | // @ts-ignore 70 | x1["f"]() 71 | 72 | 73 | // @ts-ignore 74 | async function qwe() { 75 | const x: any = {} 76 | x[p] = function () {} 77 | const s = "assert/strict" 78 | const a: any = await import(s) 79 | a.ok(true) 80 | // TODO: This is not seen. The await statement does not work properly, and approximate finishes before it is executed. 81 | x[p+p] = function () {} 82 | } -------------------------------------------------------------------------------- /tests/approx/hints-forced.json: -------------------------------------------------------------------------------- 1 | {"modules":["approx@1.0.0:hintsOnly/forced.js"],"functions":["0:49:20:54:2","0:1:1:10:2","0:5:16:5:44","0:12:1:19:2","0:17:20:17:34","0:21:1:38:2","0:25:20:25:34","0:30:20:30:34","0:36:20:36:34","0:40:1:45:2","0:47:1:47:18","0:50:24:53:6","0:59:7:65:2","0:62:15:64:6"],"reads":[],"writes":[{"type":"normal","loc":"0:50:5:53:6","baseLoc":"0:47:1:47:18","baseType":"Prototype","prop":"a","valLoc":"0:50:24:53:6","valType":"Function"},{"type":"normal","loc":"0:50:5:53:6","baseLoc":"0:47:1:47:18","baseType":"Prototype","prop":"b","valLoc":"0:50:24:53:6","valType":"Function"},{"type":"normal","loc":"0:59:1:65:2","baseLoc":"0:58:9:58:11","baseType":"Object","prop":"p","valLoc":"0:59:7:65:2","valType":"Function"},{"type":"normal","loc":"0:5:9:5:44","baseLoc":"0:3:13:3:15","baseType":"Object","prop":"get","valLoc":"0:5:16:5:44","valType":"Function"},{"type":"normal","loc":"0:5:9:5:44","baseLoc":"0:3:13:3:15","baseType":"Object","prop":"set","valLoc":"0:5:16:5:44","valType":"Function"},{"type":"normal","loc":"0:17:5:17:34","baseLoc":"0:16:13:16:15","baseType":"Object","prop":"prop","valLoc":"0:17:20:17:34","valType":"Function"},{"type":"normal","loc":"0:25:5:25:34","baseLoc":"0:22:15:22:17","baseType":"Object","prop":"p1","valLoc":"0:25:20:25:34","valType":"Function"},{"type":"normal","loc":"0:30:5:30:34","baseLoc":"0:22:15:22:17","baseType":"Object","prop":"p2","valLoc":"0:30:20:30:34","valType":"Function"},{"type":"normal","loc":"0:36:5:36:34","baseLoc":"0:22:15:22:17","baseType":"Object","prop":"p3","valLoc":"0:36:20:36:34","valType":"Function"},{"type":"normal","loc":"0:43:9:43:28","baseLoc":"0:42:19:42:21","baseType":"Object","prop":"prop","valLoc":"0:43:26:43:28","valType":"Object"},{"type":"normal","loc":"0:52:9:52:20","baseLoc":"0:51:19:51:21","baseType":"Object","prop":"p","valLoc":"0:52:18:52:20","valType":"Object"}],"requires":[],"evals":[]} -------------------------------------------------------------------------------- /src/typings/vulnerabilities.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Vulnerability description, optionally augmented by a module, a function code location, or access paths. 3 | */ 4 | export type Vulnerability = ({ 5 | osv: OpenSourceVulnerability 6 | } | { 7 | npm: NpmAuditVulnerability 8 | }) & ({ 9 | loc: { 10 | filename: string; 11 | } & ({ 12 | start: { 13 | line: number; 14 | column: number; 15 | }, 16 | end: { 17 | line: number; 18 | column: number; 19 | } 20 | } | {}); 21 | } | { 22 | patterns: Array; 23 | } | {}) 24 | 25 | /** 26 | * Open Source Vulnerability format. 27 | * From https://github.com/renovatebot/osv-offline/blob/main/packages/osv-offline-db/src/lib/osv.ts. 28 | * Fixed camelcase to underscores, added last_affected. Unused fields are omitted. 29 | */ 30 | export type OpenSourceVulnerability = { 31 | id: string; 32 | affected?: Array<{ 33 | package?: { 34 | name: string 35 | }; 36 | ranges?: Array<{ 37 | events: Array<{ 38 | introduced?: string; 39 | fixed?: string; 40 | limit?: string; 41 | last_affected?: string; 42 | }> 43 | }>; 44 | versions?: Array; 45 | }>; 46 | } 47 | 48 | /** 49 | * npm audit vulnerability format. 50 | * From https://github.com/npm/cli/blob/latest/workspaces/arborist/lib/vuln.js. 51 | * Unused fields are omitted. 52 | */ 53 | export type NpmAuditVulnerability = { 54 | name: string; // package name 55 | url: string; // typically "https://github.com/advisories/GHSA-xxxx-xxxx-xxxx" 56 | range: string; // semver range 57 | } 58 | 59 | export function getVulnerabilityId(v: Vulnerability): string { 60 | return "osv" in v ? v.osv.id : v.npm.url; 61 | } 62 | -------------------------------------------------------------------------------- /tests/micro/generators.js: -------------------------------------------------------------------------------- 1 | function* gen() { // return the function's Iterator object 2 | yield () => {console.log("1")}; // write result value to the Iterator object 3 | yield* gen2(); 4 | yield* [() => {console.log("3")}, () => {console.log("4")}]; // like for-in... 5 | } 6 | 7 | function* gen2() { 8 | yield () => {console.log("2")}; 9 | } 10 | 11 | const x = gen(); 12 | const v1 = x.next(); 13 | v1.value(); 14 | for (const v of x) 15 | v(); 16 | 17 | var q = [() => {console.log("5")}]; 18 | const y = q.values(); 19 | const v2 = y.next(); 20 | v2.value(); 21 | 22 | function* gen3() { 23 | return () => {console.log("6")}; // write result value to the Iterator object 24 | } 25 | const z = gen3(); 26 | const v3 = z.next(); 27 | v3.value(); 28 | 29 | function* gen4() { 30 | const q = yield; // yield gives value from .next 31 | q(); 32 | } 33 | const t = gen4(); 34 | t.next(); 35 | t.next(() => {console.log("7")}); 36 | 37 | function* gen5() { 38 | yield () => {console.log("8")}; 39 | return () => {console.log("9")}; 40 | } 41 | const u = gen5(); 42 | u.next().value(); 43 | u.next().value(); 44 | 45 | const obj = { 46 | *gen6 () { 47 | yield () => {console.log("10")}; 48 | } 49 | } 50 | const e = obj.gen6() 51 | e.next().value(); 52 | 53 | class Foo { 54 | *gen7() { 55 | yield () => {console.log("11")}; 56 | } 57 | } 58 | const f = new Foo(); 59 | const g = f.gen7(); 60 | g.next().value(); 61 | 62 | function* gen8() { 63 | yield* [() => {console.log("12")}, () => {console.log("13")}]; 64 | return () => {console.log("14")}; 65 | } 66 | function* gen9() { 67 | const t = yield* gen8(); // yield* gives returned value 68 | t(); 69 | return t; 70 | } 71 | const i1 = gen9(); 72 | i1.next().value(); 73 | i1.next().value(); 74 | i1.next().value(); 75 | 76 | // TODO: 77 | // x.return(() => {}); 78 | // x.throw(() => {}); 79 | -------------------------------------------------------------------------------- /tests/micro/classes2.json: -------------------------------------------------------------------------------- 1 | {"entries":["classes2.js"],"files":["classes2.js"],"functions":["0:1:1:137:1","0:1:1:3:2","0:5:1:7:2","0:2:15:2:40","0:6:15:6:40","0:4:9:4:34","0:8:9:8:34","0:20:5:20:34","0:16:1:27:2","0:29:5:32:6","0:31:19:31:44","0:20:9:20:33","0:21:5:23:6","0:24:12:26:6","0:45:12:45:22","0:46:5:48:6","0:62:12:62:22","0:63:5:65:6","0:56:1:72:2","0:44:5:44:14","0:40:1:55:2","0:61:5:61:14","0:74:5:74:30","0:75:5:75:30","0:49:5:51:6","0:66:5:68:6","0:47:19:47:42","0:64:19:64:42","0:52:12:54:6","0:69:12:71:6","0:94:5:96:6","0:93:1:97:2","0:95:19:95:42","0:101:5:103:6","0:100:1:104:2","0:102:19:102:42","0:115:9:115:34","0:116:5:116:29","0:111:11:111:36","0:118:5:120:6","0:114:20:114:52","0:129:12:129:22","0:130:5:130:15","0:128:1:133:2","0:131:5:131:29","0:132:12:132:36"],"calls":["0:9:16:9:22","0:10:12:10:20","0:11:1:11:8","0:12:1:12:8","0:13:1:13:8","0:14:1:14:8","0:28:12:33:2","0:34:1:34:8","0:35:1:35:8","0:36:1:36:7","0:37:1:37:7","0:38:1:38:6","0:73:10:76:2","0:77:1:77:8","0:78:1:78:8","0:79:1:79:10","0:80:1:80:10","0:81:1:81:8","0:82:1:82:8","0:83:1:83:7","0:84:1:84:7","0:85:1:85:7","0:86:1:86:7","0:87:1:87:7","0:88:1:88:7","0:89:1:89:10","0:90:1:90:10","0:91:1:91:10","0:98:10:98:16","0:99:1:99:8","0:105:10:105:16","0:106:1:106:8","0:107:1:107:8","0:108:1:108:8","0:122:1:122:8","0:123:1:123:8","0:124:1:124:11","0:125:1:125:13","0:125:1:125:8","0:126:1:126:7","0:134:13:134:20","0:135:1:135:12","0:136:1:136:12"],"fun2fun":[[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,8],[0,9],[0,10],[0,11],[0,12],[0,13],[0,18],[0,22],[0,23],[0,24],[0,25],[0,26],[0,27],[0,28],[0,29],[0,31],[0,32],[0,34],[0,35],[0,36],[0,37],[0,38],[0,39],[0,40],[0,43],[0,44],[0,45]],"call2fun":[[0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,8],[7,9],[8,10],[9,11],[10,12],[11,13],[12,18],[13,22],[14,23],[15,22],[16,23],[17,24],[18,25],[19,26],[20,26],[21,27],[22,28],[23,29],[24,28],[25,28],[26,28],[27,29],[28,31],[29,32],[30,34],[31,32],[32,32],[33,35],[34,36],[35,37],[36,38],[38,39],[37,37],[39,40],[40,43],[41,44],[42,45]],"ignore":[],"time":"Fri, 20 Oct 2023 08:02:51 GMT"} -------------------------------------------------------------------------------- /tests/approx/computedProperties.js: -------------------------------------------------------------------------------- 1 | /** Computed property names at object/class creation should be interpreted as dynamic property writes. */ 2 | 3 | /** Object creation. */ 4 | // Field 5 | let x = {["fo" + "o"]: function foo() {}} 6 | x.foo(); 7 | 8 | // Getter 9 | let y = {get ["message"]() {return "hello"}} 10 | console.log(y.message) 11 | 12 | // Setter 13 | let z = {set ["message"](x) {console.log(x)}} 14 | z.message = "world!" 15 | 16 | // Method 17 | const tautology = true === true; 18 | let m = { 19 | [tautology ? "tautology" : "impossible"](b) { 20 | } 21 | } 22 | m.tautology() 23 | 24 | 25 | /** Class creation. */ 26 | class A { 27 | _x; 28 | 29 | ["computedProperty"] = function () {console.log("e")} 30 | 31 | constructor(x) { 32 | this._x = x; 33 | } 34 | 35 | static ["static"+"F"] = function () {console.log("a")};// Static field 36 | static ["static"+"G"]() {console.log("e")} 37 | ["method"]() {console.log("b")}; // Method 38 | 39 | get ["field"] () {return this._x} // Getter 40 | set ["field"](x) {this._x = x} // Setter 41 | 42 | ["name" + ""]() {} // Id 'name' should not access property descriptor of Class.name 43 | } 44 | 45 | const a = new A(function foo() {console.log("c")}); 46 | A.staticF(); 47 | a.method(); 48 | let f = a.field; 49 | f(); 50 | a.field = function () {console.log("d")} 51 | a.field(); 52 | a.computedProperty() 53 | A.staticG(); 54 | a.name(); 55 | 56 | /** Nested structures. */ 57 | const arr = ["p1", "p2"]; 58 | const top = { 59 | mid: { 60 | [arr[0]]: function () {console.log("1")}, 61 | [arr[1]]() { 62 | console.log("2") 63 | } 64 | }, 65 | ["bot"]: { 66 | ["some" + "thing"]: { 67 | [arr[0]+arr[1]]: function () {console.log("3")} 68 | } 69 | }, 70 | special: { 71 | get "foo"() {console.log("4")}, 72 | set ["bar"](x) {console.log("5")} 73 | } 74 | } 75 | top.mid.p1(); 76 | top.mid.p2(); 77 | top.bot.something.p1p2(); 78 | top.special.foo; 79 | top.special.bar = "" -------------------------------------------------------------------------------- /src/output/tostringwithcode.ts: -------------------------------------------------------------------------------- 1 | import {ArgumentsVar, ConstraintVar, FunctionReturnVar, IntermediateVar, NodeVar, ObjectPropertyVar, ThisVar} from "../analysis/constraintvars"; 2 | import {codeFromLocation} from "../misc/files"; 3 | import {SourceLocation} from "@babel/types"; 4 | import {AllocationSiteToken, FunctionToken, Token} from "../analysis/tokens"; 5 | import {FunctionInfo} from "../analysis/infos"; 6 | 7 | /** 8 | * Returns a string description of the given function, with a code snippet. 9 | */ 10 | export function funcToStringWithCode(info: FunctionInfo): string { 11 | return `'${codeFromLocation(info.loc)}'${info}`; 12 | } 13 | 14 | /** 15 | * Extracts the source location from a token, or returns undefined if the token doesn't have a source location. 16 | */ 17 | export function getTokenLocation(token: Token): SourceLocation | undefined { 18 | if (token instanceof FunctionToken) { 19 | if (token.fun.loc) 20 | return token.fun.loc; 21 | } else if (token instanceof AllocationSiteToken) { 22 | if (token.allocSite.loc) 23 | return token.allocSite.loc; 24 | } 25 | return undefined; 26 | } 27 | 28 | /** 29 | * Returns a string description of the given constraint variable, with a code snippet if it has a source location. 30 | */ 31 | export function constraintVarToStringWithCode(v: ConstraintVar): string { 32 | if (v instanceof NodeVar || v instanceof IntermediateVar) { 33 | if (v.toString().startsWith("'")) 34 | return v.toString(); 35 | return `'${codeFromLocation(v.node.loc)}'${v.toString()}`; 36 | } else if (v instanceof ObjectPropertyVar) 37 | return `${v.toString()}${codeFromLocation(getTokenLocation(v.obj)) === "-" ? "" : ` (Object is "${codeFromLocation(getTokenLocation(v.obj))}")`}`; 38 | else if (v instanceof ArgumentsVar || v instanceof FunctionReturnVar || v instanceof ThisVar) 39 | return `${v.toString()}${codeFromLocation(v.fun.loc) === "-" ? "" : ` (Function is "${codeFromLocation(v.fun.loc)}")`}`; 40 | else 41 | return v.toString(); 42 | } 43 | -------------------------------------------------------------------------------- /src/analysis/modulefinder.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CallExpression, 3 | ExportAllDeclaration, 4 | ExportNamedDeclaration, 5 | File, 6 | ImportDeclaration, 7 | isIdentifier, 8 | isImport, 9 | isStringLiteral 10 | } from "@babel/types"; 11 | import traverse, {NodePath} from "@babel/traverse"; 12 | import Module from "module"; 13 | import {ModuleInfo} from "./infos"; 14 | import {FragmentState} from "./fragmentstate"; 15 | 16 | /** 17 | * Scans AST for 'require', 'import' and 'export' only (no proper analysis). 18 | */ 19 | export function findModules(ast: File, f: FragmentState, moduleInfo: ModuleInfo) { 20 | 21 | function loadModule(mode: "commonjs" | "module", str: string, path: NodePath) { // see loadModule in operations.ts 22 | if (!Module.isBuiltin(str)) 23 | f.loadModule(mode, str, path, moduleInfo); 24 | } 25 | 26 | traverse(ast, { 27 | 28 | CallExpression(path: NodePath) { 29 | const imp = isImport(path.node.callee); 30 | if ((imp || (isIdentifier(path.node.callee) && 31 | path.node.callee.name === "require" && 32 | !path.scope.getBinding(path.node.callee.name))) && 33 | path.node.arguments.length >= 1) { 34 | const arg = path.node.arguments[0]; 35 | if (isStringLiteral(arg)) 36 | loadModule(imp ? "module" : "commonjs", arg.value, path); 37 | else 38 | f.warnUnsupported(path.node, "Unhandled 'require'"); 39 | } 40 | }, 41 | 42 | ImportDeclaration(path: NodePath) { 43 | loadModule("module", path.node.source.value, path); 44 | }, 45 | 46 | ExportAllDeclaration(path: NodePath) { 47 | loadModule("module", path.node.source.value, path); 48 | }, 49 | 50 | ExportNamedDeclaration(path: NodePath) { 51 | if (path.node.source) 52 | loadModule("module", path.node.source.value, path); 53 | } 54 | }); 55 | } -------------------------------------------------------------------------------- /tests/approx/generate-approx.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # If a single file name [file.js] is specified, only regenerate for that single. Format is the file name *with* extension 4 | FILE_TO_REGEN=$1 5 | if [ -n "$FILE_TO_REGEN" ]; then 6 | echo "Regenerating hints and dynamic call graph for single file $FILE_TO_REGEN" 7 | filename_without_extension="${FILE_TO_REGEN%.js}" 8 | 9 | # Generate hints files 10 | node lib/main.js --approx-only tests/approx/hints-"$filename_without_extension".json tests/approx/"$FILE_TO_REGEN" 11 | 12 | # Generate dynamic call graphs 13 | node lib/main.js -d tests/approx/"$filename_without_extension".json tests/approx/"$FILE_TO_REGEN" --skip-graal-test 14 | exit 0 15 | fi 16 | 17 | 18 | # Regenerate hints files and dynamic call graphs for all .js files in the test directory 19 | for file in tests/approx/*.js; do 20 | echo "Regenerating hints and dynamic call graph for $file" 21 | if [ -f "$file" ]; then 22 | filename=$(basename "$file") 23 | filename_without_extension="${filename%.js}" 24 | 25 | # Generate hints files 26 | node lib/main.js --approx-only tests/approx/hints-"$filename_without_extension".json tests/approx/"$filename" 27 | 28 | # Generate dynamic call graphs 29 | node lib/main.js -d tests/approx/"$filename_without_extension".json tests/approx/"$filename" --skip-graal-test 30 | fi 31 | done 32 | 33 | for file in tests/approx/hintsOnly/*.js; do 34 | echo "Regenerating hints for $file" 35 | if [ -f "$file" ]; then 36 | filename=$(basename "$file") 37 | filename_without_extension="${filename%.js}" 38 | 39 | # Generate hints files 40 | node lib/main.js --approx-only tests/approx/hints-"$filename_without_extension".json tests/approx/hintsOnly/"$filename" 41 | fi 42 | done 43 | 44 | # TODO: Clean up instead of having specific tasks for all special cases 45 | 46 | # Regenerate for packageStructure 47 | node lib/main.js --approx-only tests/approx/hints-packageStructure.json tests/approx/packageStructure 48 | 49 | # Regenerate for typescript file 50 | node lib/main.js --approx-only tests/approx/hints-ts-file.json tests/approx/ts-file.ts 51 | -------------------------------------------------------------------------------- /src/testing/runner.ts: -------------------------------------------------------------------------------- 1 | // runs Jelly on all packages listed as dependencies in a given package.json file 2 | 3 | // usage example: 4 | // NODE_OPTIONS=--max-old-space-size=4096 node lib/testing/runner.js ../jelly-benchmarks/data/top100/package.json tmp/top100-results.json 60 ignoreDependencies 5 | 6 | import fs, {readFileSync} from "fs"; 7 | import {options} from "../options"; 8 | import {analyzeFiles} from "../analysis/analyzer"; 9 | import {dirname} from "path"; 10 | import {expand, writeStreamedStringify} from "../misc/files"; 11 | import logger, {setLogLevel} from "../misc/logger"; 12 | import AnalysisDiagnostics from "../analysis/diagnostics"; 13 | import {AnalysisStateReporter} from "../output/analysisstatereporter"; 14 | import Solver from "../analysis/solver"; 15 | 16 | const jsonFile = process.argv[2]; 17 | const outFile = process.argv[3]; 18 | const timeout = Number(process.argv[4]); 19 | const ignoreDependencies = process.argv[5] === "ignoreDependencies"; 20 | if (!jsonFile || !outFile || !timeout) { 21 | console.error("Error: Missing argument"); 22 | process.exit(-1); 23 | } 24 | 25 | (async function() { 26 | const f = JSON.parse(readFileSync(jsonFile, {encoding: "utf8"})); 27 | let count = 0; 28 | const packages = Object.keys(f.dependencies); 29 | const results: { [index: string]: AnalysisDiagnostics } = {}; 30 | for (const d of packages) { 31 | setLogLevel("info"); 32 | logger.info(`Analyzing package ${d} (${++count}/${packages.length})`); 33 | options.basedir = dirname(jsonFile); 34 | options.ignoreDependencies = ignoreDependencies; 35 | options.tty = false; 36 | options.warningsUnsupported = false; 37 | options.timeout = timeout; 38 | setLogLevel("warn"); 39 | const solver = new Solver(); 40 | await analyzeFiles(expand([`${options.basedir}/node_modules/${d}`]), solver); 41 | results[d] = solver.diagnostics; 42 | setLogLevel("verbose"); 43 | new AnalysisStateReporter(solver.fragmentState).reportLargestTokenSets(); 44 | } 45 | const fd = fs.openSync(outFile, "w"); 46 | writeStreamedStringify(results, fd, undefined, 2); 47 | fs.closeSync(fd); 48 | })(); -------------------------------------------------------------------------------- /src/analysis/listeners.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * IDs for token listeners. 3 | */ 4 | export enum TokenListener { // TODO: rename 5 | CALL_BASE, // base at method call 6 | CALL_METHOD, // callee at method call 7 | CALL_FUNCTION, // callee at (non-method) function call 8 | CALL_REQUIRE, // callee at 'require' call (direct calls only) 9 | CALL_EXTERNAL, // argument at call to external function 10 | READ_BASE, // base at property read (static) 11 | READ_BASE_DYNAMIC, // base at property read (dynamic) 12 | READ_GETTER, // getter at property read 13 | READ_GETTER_THIS, // getter at property read 14 | WRITE_BASE, // base at property write (static) 15 | WRITE_BASE_DYNAMIC, // base at property write (dynamic) 16 | WRITE_SETTER, // setter at property write 17 | WRITE_SETTER_THIS, // setter at property write 18 | WRITE_OBJECT_PATTERN_REST, // assignment at object pattern 19 | WRITE_OBJECT_PATTERN_REST_PROPERTIES, // assignment at object pattern 20 | WRITE_ARRAY_PATTERN_REST, // assignment at array pattern 21 | WRITE_ARRAY_PATTERN_REST_ARRAY, // assignment at array pattern 22 | WRITE_REQUIRE_EXTENSIONS, 23 | IMPORT_BASE, 24 | EXPORT_BASE, 25 | ANCESTORS, 26 | READ_ANCESTORS, 27 | WRITE_ANCESTORS, 28 | CLASS_FIELD, 29 | EXTENDS, 30 | READ_ITERATOR_VALUE, 31 | OBJECT_SPREAD, 32 | CALL_PROMISE_EXECUTOR, 33 | CALL_PROMISE_RESOLVE, 34 | CALL_PROMISE_ONFULFILLED, 35 | CALL_PROMISE_ONREJECTED, 36 | CALL_PROMISE_ONFINALLY, 37 | MAKE_PROMISE_RESOLVE, 38 | MAKE_PROMISE_REJECT, 39 | MAKE_PROMISE_ALL, 40 | MAKE_PROMISE_ALLSETTLED, 41 | MAKE_PROMISE_ANY, 42 | MAKE_PROMISE_RACE, 43 | AWAIT, 44 | JSX_ELEMENT, 45 | NATIVE_INVOKE_CALLBACK, 46 | NATIVE_INVOKE_CALLBACK2, 47 | NATIVE_INVOKE_CALL_APPLY2, 48 | NATIVE_INVOKE_CALL_APPLY3, 49 | NATIVE_ASSIGN_PROPERTIES, 50 | NATIVE_ASSIGN_PROPERTIES2, 51 | NATIVE_ASSIGN_PROPERTIES3, 52 | NATIVE_OBJECT_DEFINE_PROPERTY, 53 | NATIVE_OBJECT_DEFINE_PROPERTIES, 54 | NATIVE_ASSIGN_ITERATOR_MAP_VALUE_PAIRS, 55 | NATIVE_ASSIGN_BASE_ARRAY_ARRAY_VALUE_TO_ARRAY, 56 | NATIVE_RETURN_PROTOTYPE_OF, 57 | NATIVE_SET_PROTOTYPE_OF, 58 | } 59 | -------------------------------------------------------------------------------- /tests/approx/natives.js: -------------------------------------------------------------------------------- 1 | // /** Treating Object.create as an object literal creation. */ 2 | const p = "p"; 3 | var y = { 4 | f: function () { 5 | } 6 | } 7 | var x1 = Object.create(null); 8 | 9 | x1[p] = y; 10 | x1.p.f(); 11 | 12 | /** Treating Object.assign(target, sources) as a sequence of dynamic property writes for all properties defined on sources. */ 13 | const a = { 14 | foo: function () { 15 | } 16 | } 17 | const b = { 18 | bar: function () { 19 | }, 20 | baz: function () { 21 | } 22 | } 23 | 24 | const c = { 25 | get qwe () {}, 26 | set qweSet(x) {} 27 | } 28 | 29 | const x2 = {} 30 | Object.assign(x2, a, b, c) 31 | x2.foo(); 32 | x2.bar(); 33 | x2.baz(); 34 | x2.qwe; 35 | x2.qweSet = {} 36 | 37 | /** Treat Object.definePropert(y | ies) as a sequence of dynamic write operations as well. */ 38 | 39 | const x3 = { 40 | val: function () { 41 | }, 42 | otherVal: { 43 | s: false, t: function () { 44 | } 45 | } 46 | } 47 | 48 | var x4 = {} 49 | const v = "val" 50 | const desc = Object.getOwnPropertyDescriptor(x3, v); 51 | Object.defineProperty(x4, p, desc); 52 | x4.p(); 53 | 54 | Object.defineProperties(x4, Object.getOwnPropertyDescriptors(x3)); 55 | x4.val(); 56 | x4.otherVal.t(); 57 | 58 | /** Treating Function.prototype.bind as an allocation of a new function. */ 59 | 60 | function Foo() {} 61 | const bound = Foo.bind() 62 | const obj = {} 63 | obj["bo"+"und"] = bound; 64 | obj.bound(); 65 | 66 | /** Tracking arrays from native functions. */ 67 | // Natives on Array 68 | const arr1 = Array.from([function a1() {}, function a2() {}]) 69 | var x5 = {} 70 | x5["arr" + "1"] = arr1; 71 | x5.arr1[0]() 72 | x5.arr1[1]() 73 | 74 | const arr2 = Array.of(() => {}, () => {}) 75 | x5["arr"+"2"] = arr2 76 | x5.arr2[0]() 77 | x5.arr2[1]() 78 | 79 | // Natives on Array.prototype 80 | var t1 = [function a3(){}]; 81 | var t2 = [function a4(){}]; 82 | const arr3 = t2.concat(t1); 83 | x5["arr"+"3"] = arr3 84 | x5.arr3[0]() 85 | x5.arr3[1]() 86 | 87 | var t3 = [t1, t2] 88 | const arr4 = t3.flat(); 89 | x5["arr"+"4"] = t3.flat() 90 | x5.arr4[0]() 91 | x5.arr4[1]() 92 | 93 | t1 = [{p1: function () {}}, {p2: "foo"}] 94 | const arr5 = t1.filter(entry => "p1" in entry) 95 | x5["arr"+"5"] = arr5 96 | x5.arr5[0].p1(); 97 | 98 | t1 = [function () {}, "foo", "bar"] 99 | const arr6 = t1.slice(0, 1); 100 | x5["arr"+"6"] = arr6; 101 | x5.arr6[0](); 102 | 103 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 AS node-builder 2 | WORKDIR /tools 3 | 4 | # install Node & update NPM 5 | RUN apt-get update && apt-get install -y --no-install-recommends \ 6 | curl \ 7 | wget \ 8 | netcat \ 9 | ca-certificates && \ 10 | apt-get autoremove -y && \ 11 | apt-get clean && \ 12 | rm -rf /var/lib/apt/lists/* 13 | ARG NODE_VERSION=22.19.0 14 | ARG NODE_PACKAGE=node-v${NODE_VERSION}-linux 15 | RUN arch="$(dpkg --print-architecture)"; \ 16 | case "$arch" in \ 17 | amd64) export ARCH='x64' ;; \ 18 | arm64) export ARCH='arm64' ;; \ 19 | esac; \ 20 | \ 21 | wget -c https://nodejs.org/dist/v$NODE_VERSION/$NODE_PACKAGE-$ARCH.tar.gz -O -| tar -xzC /tools/ && \ 22 | mv /tools/$NODE_PACKAGE-$ARCH /tools/node && \ 23 | PATH="/tools/node/bin:$PATH" npm install -g "npm@^9.8.0" 24 | # GraalJS uses Node 16 which is not supported by npm v10 25 | 26 | FROM ubuntu:20.04 AS nodeprof-builder 27 | WORKDIR /tools 28 | 29 | # install GraalVM JavaScript and NodeProf 30 | RUN apt-get update && apt-get install -y git gcc g++ make python3 python3-pip && pip3 install ninja_syntax 31 | RUN git clone --depth=1 --branch 6.42.0 https://github.com/graalvm/mx.git 32 | RUN /tools/mx/mx fetch-jdk --java-distribution labsjdk-ce-17 --to /tools --alias jdk 33 | ENV JAVA_HOME=/tools/jdk 34 | # set up a specific version of nodeprof.js 35 | WORKDIR /tools/nodeprof.js 36 | RUN git init && \ 37 | git remote add origin https://github.com/Haiyang-Sun/nodeprof.js.git && \ 38 | git fetch origin edc3be9ea55b4fa59bb26c74e7f0d29602556c56 && \ 39 | git reset --hard FETCH_HEAD 40 | RUN /tools/mx/mx sforceimports 41 | RUN /tools/mx/mx build 42 | RUN /tools/mx/mx --dy /compiler build 43 | 44 | FROM ubuntu:20.04 45 | RUN mkdir -p /usr/lib/jvm 46 | COPY --from=node-builder /tools/node /opt/node 47 | COPY --from=nodeprof-builder /tools/jdk /usr/lib/jvm/jdk 48 | COPY --from=nodeprof-builder /tools/graal/sdk/latest_graalvm_home /usr/lib/jvm/graalvm 49 | ENV NODE_PATH=/opt/node/lib/node_modules 50 | ENV PATH=/opt/node/bin:$PATH 51 | ENV JAVA_HOME=/usr/lib/jvm/jdk 52 | ENV GRAAL_HOME=/usr/lib/jvm/graalvm 53 | ENV NODE_OPTIONS="--max-old-space-size=8192" 54 | ENV NODE_ENV=production 55 | 56 | # install Jelly files built locally 57 | RUN mkdir /jelly 58 | WORKDIR /jelly 59 | COPY ./package.json ./package-lock.json ./ 60 | COPY ./resources ./resources 61 | COPY ./bin ./bin 62 | RUN npm ci --omit=dev 63 | COPY ./lib ./lib 64 | RUN npm link 65 | ENTRYPOINT ["node", "/jelly/lib/main.js"] 66 | -------------------------------------------------------------------------------- /tests/micro/iterators.js: -------------------------------------------------------------------------------- 1 | // Array 2 | 3 | const array = [ 4 | () => {}, 5 | () => {} 6 | ]; 7 | array.push(() => {}); 8 | for (const f of array) 9 | f(); 10 | for (const f of array.values()) 11 | f(); 12 | 13 | array.forEach((v, k, ss) => { 14 | v(); 15 | ss.includes(v); 16 | }, {}); 17 | const t9 = array.pop(); 18 | t9(); 19 | const t13 = array.at(0); 20 | t13(); 21 | array.fill(() => {}, 5, 10); 22 | 23 | array.every((val, idx, arr) => {}, {}); 24 | array.some((val, idx, arr) => {}, {}); 25 | const t10 = array.find((val, idx, arr) => {}, {}); 26 | array.findIndex((val, idx, arr) => {}, {}); 27 | const a10 = array.filter((val, idx, arr) => {}, {}); 28 | a10.push(); 29 | const a11 = array.map((val, idx, arr) => {}, {}); 30 | a11.push(); 31 | const t11 = array.reduce((previousValue, currentValue, currentIndex, arr) => { 32 | currentValue(); 33 | arr.includes(); 34 | return previousValue; 35 | }, {}); 36 | console.log(t11); 37 | const t12 = array.reduceRight((previousValue, currentValue, currentIndex, arr) => { 38 | currentValue(); 39 | arr.includes(); 40 | return previousValue; 41 | }, {}); 42 | console.log(t12); 43 | const a12 = array.sort((a, b) => {}); 44 | a12.includes(); 45 | const a14 = array.concat(() => {}, () => {}); 46 | a14.includes(); 47 | const a15 = array.flatMap((value, index, array) => {}, {}); 48 | a15.includes(); 49 | const a16 = array.slice(5, 7); 50 | a16.includes(); 51 | const a17 = array.splice(3, 2); 52 | a17.includes(); 53 | // TODO: array.keys(); 54 | // TODO: array.copyWithin(); 55 | // TODO: array.flat(); 56 | // TODO: Array.from(); 57 | // TODO: Array.of(); 58 | 59 | // Set 60 | 61 | const set = new Set; 62 | set.add(() => {}); 63 | set.add(() => {}); 64 | for (const f of set) 65 | f(); 66 | for (const f of set.values()) 67 | f(); 68 | for (const [v1, v2] of set.entries()) { 69 | v1(); 70 | v2(); 71 | } 72 | set.forEach((v, k, ss) => { 73 | v(); 74 | k(); 75 | ss.has(k); 76 | }, {}); 77 | 78 | // Map 79 | 80 | const map = new Map; 81 | map.set(() => {}, () => {}); 82 | map.set(() => {}, () => {}); 83 | for (const [k,v] of map) { 84 | k(); 85 | v(); 86 | } 87 | for (const [k,v] of map.entries()) { 88 | k(); 89 | v(); 90 | } 91 | for (const k of map.keys()) 92 | k(); 93 | for (const v of map.values()) 94 | v(); 95 | map.forEach((v, k, ss) => { 96 | v(); 97 | k(); 98 | ss.has(k); 99 | }, {}); 100 | -------------------------------------------------------------------------------- /tests/approx/simple.js: -------------------------------------------------------------------------------- 1 | 2 | /** Simple dynamic read/write on object literals. */ 3 | var x1 = {}; 4 | var x2 = {f: function () {}} 5 | 6 | const prop = "qwe"; 7 | const f = "f"; 8 | 9 | x1[prop] = x2; // Dynamic write 10 | var temp = x2[f]; // Dynamic read 11 | temp(); 12 | x2[f]() // Dynamic read with call expression as parent (fixed bug) 13 | x1.qwe.f(); 14 | 15 | /** Simple dynamic read/write on functions */ 16 | 17 | function Foo() {} 18 | var x3 = () => {} 19 | // 20 | // Write/Read for Arrow and Normal function 21 | x3[prop] = Foo; 22 | Foo[prop] = x3; 23 | Foo[prop]() 24 | x3[prop](); 25 | 26 | const prop2 = "p2" 27 | 28 | /** "new" constructs */ 29 | class A {} 30 | 31 | let x4 = new Foo(); 32 | const x5 = new A(); 33 | x4[prop2] = x3; 34 | x4.p2(); 35 | x5[prop2] = x4; 36 | x5[prop2][prop2](); 37 | 38 | /** Object literal and Class creation with dynamic properties */ 39 | var x6 = { 40 | p1: function () {}, // Statically known property name 41 | [prop2]: function () {}, // Dynamically computed ObjectProperty 42 | ["p" + "3"]: function () {} // Dynamically computed ObjectProperty with string value 43 | } 44 | 45 | class C { 46 | ["my" + "Function"] () {} // Dynamic method declaration - impossible to track using NodeProf. 47 | } 48 | 49 | x6.p2(); 50 | x6.p3(); 51 | new C().myFunction(); 52 | 53 | 54 | /** Getter/Setter declarations. */ 55 | class D { 56 | get ["ba" + "z"]() {} // Computed with non-string literal expression 57 | set ["q" + "w" + "e" + "Set"](x) {} // Dynamic setter 58 | } 59 | var x7 = new D; 60 | // Function call to corresponding setter function 61 | x7.baz; 62 | x7.qweSet = x6; 63 | 64 | 65 | /** Operations involving objects from classes or new-constructs */ 66 | class E {} 67 | class F extends E { 68 | constructor() { 69 | super(); 70 | } 71 | } 72 | 73 | var x8 = new Foo(); 74 | var x9 = new F; 75 | x8[prop] = x9; 76 | x9[prop] = x2[f] 77 | x9.qwe() 78 | 79 | /** Calls to super within methods. */ 80 | class A1 { 81 | getProperty() { 82 | return "p"; 83 | } 84 | } 85 | class B1 extends A1 { 86 | setProperty(val) { 87 | this[super.getProperty()] = val; 88 | } 89 | } 90 | 91 | const b = new B1(); 92 | const val = function foo() {} 93 | b.setProperty(val) 94 | b.p(); 95 | 96 | /** Optionals - ensure non-crashing behaviour. */ 97 | const x = {} 98 | x.nonExistent?.() 99 | x.alsoNonExistent?.property; 100 | x["p" + "1"] = function() {} 101 | x.p1(); -------------------------------------------------------------------------------- /src/typings/callgraph.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Call graph created either statically or dynamically. 3 | * 4 | * Each source location has the format "::::". 5 | * Each function index, function location, call index and call location is assumed to be unique. 6 | * The edge arrays are assumed not to contain duplicate pairs. 7 | * 8 | * Be aware that some call edges may or may not be included depending on how the call graph is created: 9 | * - implicit calls to getters/setters and toString/valueOf 10 | * - calls to/from native functions, including 'eval', and event handlers 11 | * - calls to 'require' and import declarations 12 | */ 13 | import {LocationJSON} from "../misc/util"; 14 | 15 | export type CallGraph = { // TODO: represent special call edges separately from ordinary call edges? 16 | 17 | /** 18 | * Entry files (relative to basedir). 19 | */ 20 | entries?: Array, 21 | 22 | /** 23 | * If set to true, only files listed in 'files' have been analyzed. 24 | */ 25 | ignoreDependencies?: boolean, 26 | 27 | /** 28 | * Packages that have been selected for inclusion (default: all). 29 | */ 30 | includePackages?: Array, 31 | 32 | /** 33 | * Packages that have been selected for exclusion (default: none). 34 | */ 35 | excludePackages?: Array, 36 | 37 | /** 38 | * Time stamp of creation. 39 | */ 40 | time?: string, 41 | 42 | /** 43 | * Array of files (relative to basedir). 44 | * The position in the array defines the file index. 45 | */ 46 | files: Array, 47 | 48 | /** 49 | * Indices and source locations of functions. 50 | */ 51 | functions: { 52 | [index: number]: LocationJSON; 53 | }, 54 | 55 | /** 56 | * Indices and source locations of calls. 57 | */ 58 | calls: { 59 | [index: number]: LocationJSON; 60 | }, 61 | 62 | /** 63 | * Caller-callee edges, function to function. 64 | */ 65 | fun2fun: Array<[number, number]>; 66 | 67 | /** 68 | * Caller-callee edges, call site to function. 69 | */ 70 | call2fun: Array<[number, number]>; 71 | 72 | /** 73 | * Source locations of functions that should be ignored when comparing call graphs. 74 | * This is used for skipping spurious functions that appear in dynamic call graph construction 75 | * but are not known to be spurious until running static call graph construction. 76 | */ 77 | ignore?: Array; 78 | } 79 | -------------------------------------------------------------------------------- /src/analysis/accesspaths.ts: -------------------------------------------------------------------------------- 1 | import {DummyModuleInfo, ModuleInfo} from "./infos"; 2 | import {ConstraintVar} from "./constraintvars"; 3 | 4 | /** 5 | * Access paths used for describing package/module interfaces. 6 | */ 7 | export abstract class AccessPath { 8 | 9 | protected constructor(private readonly str: string) {} 10 | 11 | toString(): string { 12 | return this.str; 13 | } 14 | } 15 | 16 | /** 17 | * Access path that represents module.exports values (for exports interfaces) or require("...") values (for imports interfaces). 18 | */ 19 | export class ModuleAccessPath extends AccessPath { 20 | 21 | readonly requireName: string | undefined; 22 | 23 | constructor( 24 | readonly moduleInfo: ModuleInfo | DummyModuleInfo, 25 | requireName: string 26 | ) { 27 | const t = !"./#".includes(requireName[0]) && requireName !== moduleInfo.getOfficialName() ? requireName : undefined; // only use require name if not relative and different from official name 28 | super(`<${moduleInfo.getOfficialName()}${moduleInfo instanceof ModuleInfo ? `@${moduleInfo.packageInfo.version}` : ""}${t ? `(${t})` : ""}>`); 29 | this.requireName = t; 30 | } 31 | } 32 | 33 | /** 34 | * Access path that represents an object property. 35 | */ 36 | export class PropertyAccessPath extends AccessPath { 37 | 38 | constructor( 39 | readonly base: ConstraintVar, 40 | readonly prop: string 41 | ) { 42 | super(`${base}.${prop}`); 43 | } 44 | } 45 | 46 | /** 47 | * Access path that represents the result of a function call (possibly with 'new'). 48 | */ 49 | export class CallResultAccessPath extends AccessPath { 50 | 51 | constructor(readonly caller: ConstraintVar) { 52 | super(`${caller}()`); 53 | } 54 | } 55 | 56 | /** 57 | * Access path that represents the result of a JSX component instantiation. 58 | */ 59 | export class ComponentAccessPath extends AccessPath { 60 | 61 | constructor(readonly component: ConstraintVar) { 62 | super(`${component}<>`); 63 | } 64 | } 65 | 66 | /** 67 | * Access path that represents values from ignored modules. 68 | */ 69 | export class IgnoredAccessPath extends AccessPath { 70 | 71 | static instance = new IgnoredAccessPath(); 72 | 73 | constructor() { 74 | super("Ignored"); 75 | } 76 | } 77 | 78 | /** 79 | * Access path that represents unknown values. 80 | */ 81 | export class UnknownAccessPath extends AccessPath { 82 | 83 | static instance = new UnknownAccessPath(); 84 | 85 | constructor() { 86 | super("Unknown"); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/typings/tapir.ts: -------------------------------------------------------------------------------- 1 | // mono:tapir/src/pattern-finder/patch-description-types.ts 2 | 3 | export interface LibraryPatchDescriptionTypes { 4 | [index: string]: ClientPatchType; 5 | } 6 | 7 | export interface ClientPatchType { 8 | excludedFolders?: string[]; 9 | excludedFiles?: string[]; 10 | includedFiles?: string[]; // new 11 | patches: PatchType[]; 12 | repo: RepoType; 13 | install?: boolean; 14 | } 15 | 16 | export interface PatchType { 17 | file: string; 18 | lineNumber: number; 19 | classification: string; 20 | truePositive?: boolean; 21 | } 22 | 23 | export interface RepoType { 24 | gitCommit: string; 25 | gitURL: string; 26 | } 27 | 28 | // mono:tapir/src/pattern-finder/pattern-language.ts 29 | 30 | export interface PatternWrapper { 31 | pattern: string; 32 | question?: string; 33 | id: string; 34 | changelogId?: string; 35 | changelogDescription?: string; 36 | deprecation?: boolean; 37 | benign?: boolean; 38 | } 39 | 40 | // mono:types/semantic-patches.d.ts 41 | 42 | export type SemanticPatch = { 43 | version: number, 44 | semanticPatch: { 45 | detectionPattern: string; 46 | primaryTemplate?: any; // not used here 47 | objectModifiers?: any; // not used here 48 | alternativeTemplate?: any; // not used here 49 | suggestedFixDescription?: string; 50 | transformationQuestion?: string; 51 | unknownAccessPathQuestion?: string; 52 | extraQuestion?: string; 53 | expectedToFail?: boolean; 54 | } 55 | semanticPatchId: string, 56 | breakingChangeId: string, 57 | enabled: boolean, 58 | comment: string 59 | }; 60 | 61 | // new version of mono:types/semantic-patches.d.ts 62 | 63 | export interface SemanticPatchNew { 64 | detectionPattern: string; 65 | primaryTemplate?: any; // not used here 66 | objectModifiers?: any; // not used here 67 | alternativeTemplate?: any; // not used here 68 | suggestedFixDescription?: string; 69 | transformationQuestion?: string; 70 | unknownAccessPathQuestion?: string; 71 | extraQuestion?: string; 72 | expectedToFail?: boolean; 73 | } 74 | 75 | export type RepoMatches = [ 76 | { 77 | repo: { 78 | gitURL: string, 79 | gitCommit: string 80 | }, 81 | matches: [Match] 82 | } 83 | ]; 84 | 85 | export type Match = { 86 | file: string, 87 | semanticPatchId: string; 88 | semanticPatchVersion: number; 89 | loc: string; 90 | highConfidence: boolean, 91 | questions: [{ 92 | matchId: string, 93 | answer: "yes" | "no" | null, 94 | type: string, 95 | text: string 96 | }] 97 | }; 98 | --------------------------------------------------------------------------------