From 41c6452342b31f606ee5fb9c4c50c6bc2d867e76 Mon Sep 17 00:00:00 2001 From: wessberg Date: Thu, 7 Mar 2019 00:36:01 +0100 Subject: [PATCH] fix(bug): fixes an issue with ArrayLiteralExpressions and iterables. --- CODE_OF_CONDUCT.md | 26 +-- CONTRIBUTING.md | 2 +- LICENSE.md | 4 +- README.md | 120 +++++++++-- README_old.md | 195 ++++++++++++++++++ package.json | 97 ++++----- prettier.config.js | 1 + scaffold.config.js | 8 + .../evaluate-array-literal-expression.ts | 13 +- src/interpreter/i-evaluate-options.ts | 1 + .../array-literal-expression.test.ts | 20 ++ test/setup.ts | 19 +- tslint.json | 6 +- 13 files changed, 416 insertions(+), 96 deletions(-) create mode 100644 README_old.md create mode 100644 prettier.config.js create mode 100644 scaffold.config.js create mode 100644 test/array-literal-expression/array-literal-expression.test.ts diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b00a034..df948d7 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -14,21 +14,21 @@ Our Standards Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or -advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting Our Responsibilities @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting any of the code of conduct enforcers: [Frederik Wessberg](mailto:frederikwessberg@hotmail.com). +reported by contacting any of the code of conduct enforcers: [Frederik Wessberg](mailto:frederikwessberg@hotmail.com) ([@FredWessberg](https://twitter.com/FredWessberg)) ([Website](https://github.com/wessberg)). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. @@ -68,4 +68,4 @@ members of the project's leadership. Attribution This Code of Conduct is adapted from the Contributor Covenant, version 1.4, -available at http://contributor-covenant.org/version/1/4/ \ No newline at end of file +available at http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 56f7f54..6503ebf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,4 +6,4 @@ You are more than welcome to contribute to `@wessberg/ts-evaluator` in any way y - Fixing issues and suggesting new features - Blogging, tweeting, and creating tutorials about `@wessberg/ts-evaluator` - Reaching out to [@FredWessberg](https://twitter.com/FredWessberg) on Twitter -- Submit an issue or a Pull Request \ No newline at end of file +- Submit an issue or a Pull Request diff --git a/LICENSE.md b/LICENSE.md index 4f0a298..e5df0c8 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright © 2018 Frederik Wessberg +Copyright © 2019 [Frederik Wessberg](mailto:frederikwessberg@hotmail.com) ([@FredWessberg](https://twitter.com/FredWessberg)) ([Website](https://github.com/wessberg)) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE \ No newline at end of file +SOFTWARE diff --git a/README.md b/README.md index 2dc31c5..3db3ce1 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,33 @@ -Logo for @wessberg/ts-evaluator
-Downloads per month -Dependencies -NPM Version -Contributors -MIT License -Support on Patreon + + +
Logo
+ + + + > An interpreter for Typescript that can evaluate an arbitrary Node within a Typescript AST + + + + +Downloads per month +NPM version +Dependencies +Contributors +code style: prettier +License: MIT +Support on Patreon + + + + + ## Description + + This library is an implementation of an interpreter for Typescript that can evaluate any `Expression`, `ExpressionStatement` or `Declaration` within a Typescript AST. Rather than interpreting a _program_, or a sequence of `Statement`s, this library takes a Node within an existing AST and evaluates it based on its' lexical environment. @@ -24,6 +42,44 @@ Additionally, `ts-evaluator` supports both a Browser environment, a Node environ If you are looking for a Typescript REPL, or a way to _execute_ a full Typescript program, you're looking for something like [ts-node](https://github.com/TypeStrong/ts-node) instead. + + +### Features + + + +- Evaluate _any_ Node within a Typescript AST and get an actual value back +- Supports browser-, node, and ECMA environments. +- Supports several reporting- and diagnostic hooks you can use use +- Is a full-featured JavaScript virtual machine +- Supports policy restrictions and sandboxing + + + + + + + +## Table of Contents + +- [Description](#description) + - [Features](#features) +- [Table of Contents](#table-of-contents) +- [Install](#install) + - [NPM](#npm) + - [Yarn](#yarn) +- [Usage](#usage) +- [Contributing](#contributing) +- [Maintainers](#maintainers) +- [Backers](#backers) + - [Patreon](#patreon) +- [FAQ](#faq) +- [License](#license) + + + + + ## Install ### NPM @@ -38,8 +94,14 @@ $ npm install @wessberg/ts-evaluator $ yarn add @wessberg/ts-evaluator ``` + + + + ## Usage + + Let's start off with a very basic example: ```typescript @@ -178,18 +240,52 @@ Here's an explainer of the different reporting hooks: - `reportIntermediateResults(entry: IIntermediateResultReportEntry) => void|(Promise)` - Will be invoked for each intermediate result that has been evaluated before producing a final result. This allows you to work programmatically with all expression values during code execution. - `reportErrors(entry: IErrorReportEntry) => void|(Promise)` - Will be invoked for each error that is thrown, both when evaluating a result, and for subsequent invocations on, for example, returned function instances. Holds a reference to the error, as well ast the AST node that threw or caused the Error. + + ## Contributing Do you want to contribute? Awesome! Please follow [these recommendations](./CONTRIBUTING.md). + + + + ## Maintainers -- Frederik Wessberg [Frederik Wessberg](https://github.com/wessberg): _Maintainer_ +| Frederik Wessberg | +| --------------------------------------------------------------------------------------------------------------------------------- | +| [Frederik Wessberg](mailto:frederikwessberg@hotmail.com)
[@FredWessberg](https://twitter.com/FredWessberg)
_Lead Developer_ | + + + + + +## Backers + +### Patreon + +[Become a backer](https://www.patreon.com/bePatron?u=11315442) and get your name, avatar, and Twitter handle listed here. + +Backers on Patreon + + + + + +## FAQ + + + +### How fast is this? + +This is, after all, a virtual machine written on top of another virtual machine (V8), which is built in a dynamically typed high-level language (EcmaScript). This library is _not_ built to be +comparable in performance to raw V8 execution speed. However, since `ts-evaluator` doesn't require a compile-step and works directly on an AST, for small operations it will most likely be several magnitudes faster than +both `ts-node` and compiling to JavaScript with `tsc` and executing directly. -## Backers 🏅 + -[Become a backer](https://www.patreon.com/bePatron?u=11315442) and get your name, logo, and link to your site listed here. +## License -## License 📄 +MIT © [Frederik Wessberg](mailto:frederikwessberg@hotmail.com) ([@FredWessberg](https://twitter.com/FredWessberg)) ([Website](https://github.com/wessberg)) -MIT © [Frederik Wessberg](https://github.com/wessberg) + diff --git a/README_old.md b/README_old.md new file mode 100644 index 0000000..2dc31c5 --- /dev/null +++ b/README_old.md @@ -0,0 +1,195 @@ +Logo for @wessberg/ts-evaluator
+Downloads per month +Dependencies +NPM Version +Contributors +MIT License +Support on Patreon + +> An interpreter for Typescript that can evaluate an arbitrary Node within a Typescript AST + +## Description + +This library is an implementation of an interpreter for Typescript that can evaluate any `Expression`, `ExpressionStatement` or `Declaration` within a Typescript AST. +Rather than interpreting a _program_, or a sequence of `Statement`s, this library takes a Node within an existing AST and evaluates it based on its' lexical environment. + +This makes the library an effective companion if you're building a linter, framework, language service, partial evaluator, or something else where you may want to know the +computed value of a specific Node at any point in an AST. + +One strength of this plugin is that it opens up entirely new use cases such as partial evaluation directly in the editor experience, for example to catch non-syntactic bugs that would +only occur on runtime, or more advanced diagnostic for frameworks. + +To that end, several _policy_ options can be provided to configure restrictions in terms of what is allowed to be evaluated, such as IO and Network access. +Additionally, `ts-evaluator` supports both a Browser environment, a Node environment, and a pure ECMAScript environment. See [Setting up an environment](#setting-up-an-environment) for more details. + +If you are looking for a Typescript REPL, or a way to _execute_ a full Typescript program, you're looking for something like [ts-node](https://github.com/TypeStrong/ts-node) instead. + +## Install + +### NPM + +``` +$ npm install @wessberg/ts-evaluator +``` + +### Yarn + +``` +$ yarn add @wessberg/ts-evaluator +``` + +## Usage + +Let's start off with a very basic example: + +```typescript +import {evaluate} from "@wessberg/ts-evaluator"; + +const result = evaluate({ + node: someNode, + typeChecker: someTypeChecker +}); + +// If a value was produced +if (result.success) { + console.log(result.value); +} + +// If an error occurred +else { + console.log(result.reason); +} +``` + +In this example, the referenced bindings within the lexical environment of the Node will be discovered and evaluated before producing a final value. This means that +you don't have to evaluate the entire program to produce a value which may potentially be a much faster operation. + +### Setting up an environment + +You can define the kind of environment that `evaluate()` assumes when evaluating the given Node. By default, a `Node` environment is assumed. + +The following environment presets are supported: + +- `ECMA` - Assumes a pure ECMAScript environment. This means that no other globals than those that are defined in the ECMAScript spec such as `Math`, `Promise`, `Object`, etc, are available. +- `NODE` _(default)_ - Assumes a Node environment. This means that built-in modules such as `fs` and `path` can be resolved, and Node-specific globals such as `process` is present. +- `BROWSER` - Assumes a Browser environment. This means that DOM APIs are available and Browser-specific globals such as `window` is present. + +Beyond presets, you can provide additional globals or override those that comes from the presets. +Here's how you can configure environment options: + +```typescript +const result = evaluate({ + // ... + environment: { + // The "Node" environment is the default one. You can simply omit this key if you are targeting a Node environment + preset: EnvironmentPresetKind.NODE, + extra: { + someGlobal: "someValue" + } + } +}); +``` + +### Setting up Policies + +With great power comes great responsibility. If you are embedding this plugin in, say, a language service plugin to enhance the editing experience in an editor, +you may want to apply some restrictions as to what can be evaluated. + +By default, IO writes, network calls, and spawning child processes are restricted. You can customize this to your liking: + +```typescript +const result = evaluate({ + // ... + policy: { + deterministic: false, + network: false, + console: false, + maxOps: Infinity, + maxOpDuration: Infinity, + io: { + read: true, + write: false + }, + process: { + exit: false, + spawnChild: false + } + } +}); +``` + +Here's an explainer of the individual policies: + +- `deterministic` _(default: `false`)_ - If `deterministic` is `true`, only code constructs that always evaluate to the same value is permitted. This means that things like `Math.random()` or `new Date()` without arguments, as well as network calls are restricted. + This is useful if you are trying to statically analyze something and need to make sure that the value won't change for each invocation. + +- `network` _(default: `false`)_ - If `network` is `true`, network activity is allowed, such as sending an HTTP request or hooking up a server. + +- `console` _(default: `false`)_ - If `console` is `true`, logging to the console within evaluated code will produce the side-effect of actually logging to the console of the parent process. Usually, this is unwanted, since you're most likely only interested in the + evaluated value, not so much the side-effects, but you can override this behavior by setting `console` to `true`. + +- `maxOps` _(default: `Infinity`)_ - If `maxOps` is anything less than Infinity, evaluation will stop when the provided amount of operations has been performed. This is useful to opt-out of running CPU-intensive code, especially if you are embedding this library in an editor or a linter. + +- `maxOpDuration` _(default: `Infinity`)_ - If `maxOpDuration` is anything less than Infinity, evaluation will stop when the provided amount of milliseconds have passed. This is useful to opt-out of long-running operations, especially if you are embedding this library in an editor or a linter. + +- `io` _(default: `{read: true, write: false}`)_ - If `io` permits `READ` operations, files can be read from disk. If `io` permits `WRITE` operations, files can be written to disk. + +- `process` _(default: `{exit: false, spawnChild: false}`)_ - If `process` permits `exit` operations, the evaluated code is permitted to exit the parent process. If `process` permits `spawnChild` operations, the evaluated code is permitted to spawn child processes. + +### Logging + +You can get information about the evaluation process with various levels of logging. By default, nothing is logged, but you can override this behavior: + +```typescript +const result = evaluate({ + // ... + logLevel: LogLevelKind.DEBUG +}); +``` + +Here's an explainer of the different log levels: + +- `LogLevelKind.SILENT` _(default)_ - By default, nothing is logged to the console. +- `LogLevelKind.INFO` - Intermediate results are logged to the console. +- `LogLevelKind.VERBOSE` - Everything that is logged with `LogLevelKind.INFO` as well as lexical environment bindings are logged to the console +- `LogLevelKind.DEBUG` - Everything that is logged with `LogLevelKind.VERBOSE` as well as all visited Nodes during evaluation are logged to the console + +### Reporting + +You can tap into the evaluation process with reporting hooks that will be invoked with useful information while an evaluation is in progress. +These are useful if you want to understand more about the execution path and work with it programmatically. + +```typescript +const result = evaluate({ + // ... + reporting: { + reportBindings: entry => doSomething(entry), + reportTraversal: entry => someArray.push(entry.node), + reportIntermediateResults: entry => doSomeOtherThing(entry), + reportErrors: entry => doSomethingWithError(entry) + } +}); +``` + +Here's an explainer of the different reporting hooks: + +- `reportBindings(entry: IBindingReportEntry) => void|(Promise)` - Will be invoked for each time a value is bound to the lexical environment of a Node. This is useful to track mutations throughout code execution, for example to understand when and where variables are declared and/or mutated. +- `reportTraversal(entry: ITraversalReportEntry) => void|(Promise)` - Will be invoked for each time a new Node is visited while evaluating. This is useful to track the path through the AST, for example to compute code coverage. +- `reportIntermediateResults(entry: IIntermediateResultReportEntry) => void|(Promise)` - Will be invoked for each intermediate result that has been evaluated before producing a final result. This allows you to work programmatically with all expression values during code execution. +- `reportErrors(entry: IErrorReportEntry) => void|(Promise)` - Will be invoked for each error that is thrown, both when evaluating a result, and for subsequent invocations on, for example, returned function instances. Holds a reference to the error, as well ast the AST node that threw or caused the Error. + +## Contributing + +Do you want to contribute? Awesome! Please follow [these recommendations](./CONTRIBUTING.md). + +## Maintainers + +- Frederik Wessberg [Frederik Wessberg](https://github.com/wessberg): _Maintainer_ + +## Backers 🏅 + +[Become a backer](https://www.patreon.com/bePatron?u=11315442) and get your name, logo, and link to your site listed here. + +## License 📄 + +MIT © [Frederik Wessberg](https://github.com/wessberg) diff --git a/package.json b/package.json index c6c6479..cbef891 100644 --- a/package.json +++ b/package.json @@ -3,34 +3,26 @@ "version": "0.0.18", "description": "An interpreter for Typescript that can evaluate an arbitrary Node within a Typescript AST", "scripts": { - "generate:readme": "scaffold readme --blacklist intro,faq", - "generate:license": "scaffold license", - "generate:contributing": "scaffold contributing", - "generate:coc": "scaffold coc", + "generate:readme": "scaffold readme --yes", + "generate:license": "scaffold license --yes", + "generate:contributing": "scaffold contributing --yes", + "generate:coc": "scaffold coc --yes", "generate:changelog": "standard-changelog --first-release", - "generate:all": "npm run generate:license & npm run generate:contributing & npm run generate:coc & npm run generate:readme & npm run generate:changelog", - "update": "ncu -ua && npm update && npm install", - "lint": "tsc --noEmit && tslint -c tslint.json --project tsconfig.json", + "generate:all": "npm run generate:license & npm run generate:contributing & npm run generate:coc & npm run generate:readme && npm run generate:changelog", "clean:dist": "rm -rf dist", "clean:compiled": "rm -rf compiled", "clean": "npm run clean:dist && npm run clean:compiled", - "rollup": "rollup -c rollup.config.js", - "rollup:watch": "rollup -c rollup.config.js --watch", - "tsc:test": "tsc --module commonjs --target es2017 --sourceMap", - "prebuild": "npm run clean", - "prewatch": "npm run prebuild", - "build": "npm run rollup", - "build:test": "npm run tsc:test", - "watch": "npm run tsc:cjs -- --watch & npm run tsc:esm -- --watch", - "prepare": "npm run build", - "publish:pre": "NODE_ENV=production npm run lint && NODE_ENV=production npm run prepare", - "publish:meta": "npm run generate:all && git add . && (git commit -am \"Bumped version\" || true) && git push", - "publish:patch": "npm run publish:pre && npm version patch && npm run publish:meta && npm publish", - "publish:minor": "npm run publish:pre && npm version minor && npm run publish:meta && npm publish", - "publish:major": "npm run publish:pre && npm version minor && npm run publish:meta && npm publish", - "pretest": "npm run clean:compiled && npm run build:test", + "lint": "tsc --noEmit && tslint -c tslint.json --project tsconfig.json", + "prettier": "prettier --write '{src,test,documentation}/**/*.{js,ts,json,html,xml,css,md}'", + "pretest": "npm run clean:compiled && tsc --module commonjs --target es2017 --sourceMap", "test": "ava **/*.test.* --fail-fast", - "posttest": "npm run clean:compiled" + "posttest": "npm run clean:compiled", + "prebuild": "npm run clean:dist", + "build": "npm run rollup", + "rollup": "rollup -c rollup.config.js", + "preversion": "npm run lint && NODE_ENV=production npm run build", + "version": "npm run generate:all && git add .", + "release": "np --no-cleanup --no-yarn" }, "keywords": [ "typescript", @@ -43,34 +35,44 @@ "files": [ "dist/**/*.*" ], - "author": { - "name": "Frederik Wessberg", - "email": "frederikwessberg@hotmail.com", - "url": "https://github.com/wessberg" - }, + "contributors": [ + { + "name": "Frederik Wessberg", + "email": "frederikwessberg@hotmail.com", + "url": "https://github.com/wessberg", + "imageUrl": "https://avatars2.githubusercontent.com/u/20454213?s=460&v=4", + "role": "Lead Developer", + "twitter": "FredWessberg" + } + ], "license": "MIT", "devDependencies": { - "@wessberg/scaffold": "1.0.5", - "@wessberg/rollup-plugin-ts": "1.1.16", - "@wessberg/ts-config": "0.0.34", - "npm-check-updates": "2.15.0", - "standard-changelog": "2.0.6", - "tslint": "5.12.0", - "ava": "1.0.1" + "@wessberg/scaffold": "1.0.17", + "@wessberg/rollup-plugin-ts": "1.1.34", + "@wessberg/ts-config": "0.0.39", + "standard-changelog": "2.0.7", + "tslint": "5.13.1", + "ava": "1.3.1", + "prettier": "^1.16.4", + "pretty-quick": "^1.10.0", + "husky": "^1.3.1", + "np": "^4.0.2", + "find-up": "^3.0.0" }, "dependencies": { "@types/deasync": "0.1.0", - "@types/node": "10.12.18", - "@types/object-path": "0.9.29", - "chalk": "2.4.1", + "@types/node": "11.10.5", + "@types/object-path": "0.11.0", + "@types/find-up": "^2.1.1", + "chalk": "2.4.2", "deasync": "0.1.14", "object-path": "0.11.4", "tslib": "1.9.3", - "typescript": "3.2.2" + "typescript": "3.3.3333" }, "optionalDependencies": { - "@types/jsdom": "12.2.1", - "jsdom": "13.1.0" + "@types/jsdom": "12.2.3", + "jsdom": "13.2.0" }, "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", @@ -87,18 +89,5 @@ }, "engines": { "node": ">=10.1.0" - }, - "scaffold": { - "patreonUserId": "11315442", - "logo": "https://raw.githubusercontent.com/wessberg/ts-evaluator/master/documentation/asset/ts-evaluator-logo.png", - "contributorMeta": { - "Frederik Wessberg": { - "imageUrl": "https://avatars2.githubusercontent.com/u/20454213?s=460&v=4", - "role": "Maintainer", - "twitterHandle": "FredWessberg", - "isCocEnforcer": true - } - }, - "backers": [] } } diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000..761a1ff --- /dev/null +++ b/prettier.config.js @@ -0,0 +1 @@ +module.exports = require("@wessberg/ts-config/prettier.config"); diff --git a/scaffold.config.js b/scaffold.config.js new file mode 100644 index 0000000..6748bf7 --- /dev/null +++ b/scaffold.config.js @@ -0,0 +1,8 @@ +module.exports = { + ...require("@wessberg/ts-config/scaffold.config"), + logo: { + url: + "https://raw.githubusercontent.com/wessberg/ts-evaluator/master/documentation/asset/ts-evaluator-logo.png", + height: 120 + } +}; diff --git a/src/interpreter/evaluator/evaluate-array-literal-expression.ts b/src/interpreter/evaluator/evaluate-array-literal-expression.ts index 6aadda5..0128bed 100644 --- a/src/interpreter/evaluator/evaluate-array-literal-expression.ts +++ b/src/interpreter/evaluator/evaluate-array-literal-expression.ts @@ -1,8 +1,8 @@ import {IEvaluatorOptions} from "./i-evaluator-options"; -import {ArrayLiteralExpression} from "typescript"; +import {ArrayLiteralExpression, isSpreadElement} from "typescript"; import {Literal} from "../literal/literal"; -import {isIterable} from "../util/iterable/is-iterable"; import {getFromLexicalEnvironment} from "../lexical-environment/lexical-environment"; +import {isIterable} from "../util/iterable/is-iterable"; /** * Evaluates, or attempts to evaluate, a ArrayLiteralExpression @@ -16,8 +16,13 @@ export function evaluateArrayLiteralExpression ({node, environment, evaluate, st for (const element of node.elements) { const nextValue = evaluate.expression(element, environment, statementTraversalStack); - if (isIterable(nextValue)) value.push(...nextValue); - else value.push(nextValue); + if (isSpreadElement(element) && isIterable(nextValue)) { + value.push(...nextValue); + } + + else { + value.push(nextValue); + } } return value; diff --git a/src/interpreter/i-evaluate-options.ts b/src/interpreter/i-evaluate-options.ts index 8bfbbf8..0fb2986 100644 --- a/src/interpreter/i-evaluate-options.ts +++ b/src/interpreter/i-evaluate-options.ts @@ -4,6 +4,7 @@ import {IEvaluatePolicy} from "./policy/i-evaluate-policy"; import {IEnvironment} from "./environment/i-environment"; import {ReportingOptions} from "./reporting/i-reporting-options"; + export interface IEvaluateOptions { node: Statement|Declaration|Expression; typeChecker: TypeChecker; diff --git a/test/array-literal-expression/array-literal-expression.test.ts b/test/array-literal-expression/array-literal-expression.test.ts new file mode 100644 index 0000000..642fe35 --- /dev/null +++ b/test/array-literal-expression/array-literal-expression.test.ts @@ -0,0 +1,20 @@ +import test from "ava"; +import {prepareTest} from "../setup"; + +test("Can handle ArrayLiteralExpressions. #1", t => { + // noinspection BadExpressionStatementJS + const {evaluate} = prepareTest( + // language=TypeScript + ` + (["foo", "bar"]) + `, + "([" + ); + + const result = evaluate(); + + if (!result.success) t.fail(result.reason.stack); + else { + t.deepEqual(result.value as string[], ["foo", "bar"]); + } +}); \ No newline at end of file diff --git a/test/setup.ts b/test/setup.ts index 8b7f8ff..e779f93 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -3,9 +3,11 @@ import {evaluate} from "../src/interpreter/evaluate"; import {EvaluateResult} from "../src/interpreter/evaluate-result"; import {CompilerOptions, createProgram, createSourceFile, Expression, forEachChild, getDefaultCompilerOptions, getDefaultLibFileName, Node, NodeArray, ScriptKind, ScriptTarget, SourceFile, Statement, sys} from "typescript"; import {IEvaluatePolicy} from "../src/interpreter/policy/i-evaluate-policy"; -import {readFileSync} from "fs"; +import {readFileSync, readdirSync} from "fs"; import {IEnvironment} from "../src/interpreter/environment/i-environment"; import {ReportingOptions} from "../src/interpreter/reporting/i-reporting-options"; +import {sync} from "find-up" +import {join} from "path"; // tslint:disable:no-any @@ -65,12 +67,19 @@ export function prepareTest ( logLevel = LogLevelKind.SILENT }: Partial = {}): ITestFileResult { const arrFiles = Array.isArray(files) ? files : [files]; + const nodeTypesDir = sync("node_modules/@types/node"); + const nodeTypeDeclarationFiles = nodeTypesDir == null + ? [] + : readdirSync(nodeTypesDir) + .filter(file => file.endsWith(".d.ts")) + .map(file => join(nodeTypesDir, file)); + const normalizedFiles: ITestFile[] = [ ...arrFiles.map(file => typeof file === "string" ? ({text: file, fileName: `auto-generated-${Math.floor(Math.random() * 100000)}.ts`}) : file), - { - fileName: "node_modules/@types/node/index.d.ts", - text: readFileSync("node_modules/@types/node/index.d.ts").toString() - } + ...nodeTypeDeclarationFiles.map(file => ({ + fileName: file, + text: readFileSync(file, "utf8") + })) ]; const normalizedEntry = typeof entry === "string" || entry == null ? {fileName: normalizedFiles[0].fileName, match: entry == null ? "" : entry} : entry; diff --git a/tslint.json b/tslint.json index 05e7780..c6ad596 100644 --- a/tslint.json +++ b/tslint.json @@ -1,14 +1,10 @@ { - "extends": "./node_modules/@wessberg/ts-config/tslint/tslint.json", + "extends": "./node_modules/@wessberg/ts-config/tslint.json", "linterOptions": { "exclude": [ "dist/**/*.*", "compiled/**/*.*", "test123/**/*.*" ] - }, - "rules": { - "interface-name": false, - "completed-docs": false } } \ No newline at end of file