Repository: Idered/typescript-expect-plugin
Branch: master
Commit: 8e2674460c99
Files: 17
Total size: 19.3 KB
Directory structure:
gitextract_2hbh9kz3/
├── .github/
│ └── workflows/
│ └── main.yml
├── .gitignore
├── .vscode/
│ └── settings.json
├── LICENSE
├── README.md
├── package.json
├── src/
│ ├── adapter.ts
│ ├── consts.ts
│ ├── get-expect-tag.ts
│ ├── get-temporary-file.ts
│ ├── index.ts
│ ├── language-service-proxy-builder.ts
│ ├── message-bag.ts
│ ├── parse-comment.ts
│ ├── plugin-module-factory.ts
│ └── visit.ts
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/main.yml
================================================
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Begin CI...
uses: actions/checkout@v2
- name: Use Node 12
uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Use cached node_modules
uses: actions/cache@v1
with:
path: node_modules
key: nodeModules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
nodeModules-
- name: Install dependencies
run: yarn install --frozen-lockfile
env:
CI: true
- name: Build
run: yarn build
env:
CI: true
================================================
FILE: .gitignore
================================================
node_modules
lib
*.log
================================================
FILE: .vscode/settings.json
================================================
{
"editor.formatOnSave": true,
"typescript.tsdk": "node_modules\\typescript\\lib"
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 Kasper Mikiewicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
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.
================================================
FILE: README.md
================================================
<h1 align="center">Typescript Expect Plugin</h1>
<p align="center">
<img alt="npm" src="https://img.shields.io/npm/v/typescript-expect-plugin?color=blue" />
<img alt="mit license" src="https://img.shields.io/npm/l/typescript-expect-plugin?color=blue" />
<img
alt="CI"
src="https://github.com/Idered/typescript-expect-plugin/workflows/CI/badge.svg?event=push"
/>
<a
href="https://gitter.im/typescript-expect-plugin/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge"
><img
alt="Gitter"
src="https://badges.gitter.im/typescript-expect-plugin/community.svg"
/></a>
<a href="https://twitter.com/intent/follow/?screen_name=Idered">
<img alt="twitter" src="https://img.shields.io/twitter/follow/Idered?style=social" />
</a>
</p>
<p align="center">Be lazy, write simple tests in comments.</p>
<p align="center">
<img src="https://i.imgur.com/AhQK9Pl.gif" />
</p>
## Editor support
✅ VS Code - flawlessly works in `Problems` panel.
⏹ Sublime Text - could not get it to work but it might be possible.
❔ Atom - not tested.
⛔ `tsc` - plugins are disabled during build. It should work with webpack ts loader.
## Quick start
```sh
npm install typescript-expect-plugin
```
1. Add plugin to `tsconfig.json`:
```ts
{
"compilerOptions": {
"plugins": [{ "name": "typescript-expect-plugin" }]
},
}
```
2. Change VS Code typescript to workspace version:

## Usage
## WARNING
> ⚠Tests are executed after each file change - not save. Be careful if you're going to test functions that remove or change files in your local system
---
This plugin adds support for `@expect` JSDoc tag. It has the following usage pattern:
```tsx
/**
* @expect [PARAMS] CONDITION CONDITION_PARAMETER
*/
```
- `[PARAMS]` - for example `[2, 4]` will spread two arguments to tested function.
- `CONDITION` - check function from jest expect library. Use `ctrl+space` to see autocomplete suggestions.
- `CONDITION_PARAMETER` - argument passed to `CONDITION` function.
## Examples
```tsx
/**
* @expect [2, 4] toBe 6
* @expect [2, 2] toBeGreaterThan 3
* @expect [2, 2] toBeLessThan 3
* @expect [2, 22] toEqual 24
*/
export function sum(a: number, b: number) {
return a + b;
}
/**
* @expect [[2, 4, 8], 4] toBeTruthy
* @expect [[2, 4, 8], 12] toBeFalsy
*/
export function has(haystack: any[], needle: any) {
return haystack.includes(needle);
}
/**
* @expect [[2, 8], [9, 12]] toEqual [2, 8, 9, 12]
*/
export function join(arr1: any[], arr2: any[]) {
return [...arr1, ...arr2];
}
/**
* @expect [{"firstName": "John"}, "lastName", "Doe"] toHaveProperty "lastName", "Doe Doe"
*/
export function withProp(obj: Record<string, any>, key: string, value: any) {
return {...obj, [key]: value}
}
```
> ### Test objects

> ### Test arrays

## Author
Hey there, I'm Kasper. If you wish to get notified about more cool typescript or react projects/tips you can follow me on twitter.
<a href="https://twitter.com/intent/follow/?screen_name=Idered">
<img alt="twitter" src="https://img.shields.io/twitter/follow/Idered?style=social" />
</a>
================================================
FILE: package.json
================================================
{
"name": "typescript-expect-plugin",
"description": "Be lazy, write simple tests in comments",
"version": "0.3.1",
"main": "lib/index.js",
"author": "Kasper Mikiewicz",
"license": "MIT",
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"prepare": "tsc"
},
"files": [
"lib"
],
"keywords": [
"typescript",
"typescript-plugin",
"test",
"jest",
"expect"
],
"repository": {
"type": "git",
"url": "git+https://github.com/idered/typescript-expect-plugin.git"
},
"homepage": "https://github.com/idered/typescript-expect-plugin#readme",
"bugs": {
"url": "https://github.com/idered/typescript-expect-plugin/issues"
},
"engines": {
"node": ">=10"
},
"dependencies": {
"byots": "^4.0.0-dev.20200523.13.57",
"expect": "^26.0.1",
"read-pkg-up": "^7.0.1",
"tmp": "^0.2.1",
"ts-node": "^8.10.1"
},
"peerDependencies": {
"typescript": ">=3.7.0"
},
"devDependencies": {
"@types/node": "^14.0.1",
"@types/tmp": "^0.2.0",
"typescript": "^3.9.2"
}
}
================================================
FILE: src/adapter.ts
================================================
import ts, { ScriptElementKind } from "typescript";
import bts from "byots";
import { register } from "ts-node";
import visit from "./visit";
import { MessageBag } from "./message-bag";
import {
EXPECT_KEYWORDS,
TS_LANGSERVICE_EXPECT_DIAGNOSTIC_ERROR_CODE,
} from "./consts";
register({
compilerOptions: {
target: "ESNext",
},
});
export type ESLintAdapterOptions = {
logger: (msg: string) => void;
getSourceFile: (fileName: string) => ts.SourceFile | undefined;
getProgram?: () => ts.Program;
};
export class Adapter {
private readonly logger: (msg: string) => void;
private readonly getSourceFile: (
fileName: string
) => ts.SourceFile | undefined;
private messageBag: MessageBag;
public constructor({ logger, getSourceFile }: ESLintAdapterOptions) {
this.logger = logger;
this.getSourceFile = getSourceFile;
this.messageBag = new MessageBag();
}
public getSemanticDiagnostics(
delegate: ts.LanguageService["getSemanticDiagnostics"],
fileName: string
): ReturnType<ts.LanguageService["getSemanticDiagnostics"]> {
const original = delegate(fileName);
try {
this.messageBag.clear();
const sourceFile = this.getSourceFile(fileName);
if (!sourceFile) return original;
visit(sourceFile, this.messageBag);
const diagnostics = original.length
? []
: this.transformErrorsToDiagnostics(sourceFile);
return [...original, ...diagnostics];
} catch (error) {
this.logger(error.message ? error.message : "unknown error");
return original;
}
}
public getCompletionsAtPosition(
delegate: ts.LanguageService["getCompletionsAtPosition"],
fileName: string,
position: number,
options: ts.GetCompletionsAtPositionOptions
): ReturnType<ts.LanguageService["getCompletionsAtPosition"]> {
let original = delegate(fileName, position, options);
const source = (this.getSourceFile(fileName) as unknown) as bts.SourceFile;
const token = bts.getTokenAtPosition(source, position);
if (bts.isJSDocTag(token) && original) {
original.entries = [
...original.entries,
{
kind: ScriptElementKind.keyword,
kindModifiers: "",
name: "expect",
sortText: "0",
},
];
}
if (bts.isInComment(source, position) && bts.isJSDoc(token)) {
if (!original) {
original = {
entries: [],
isGlobalCompletion: false,
isMemberCompletion: false,
isNewIdentifierLocation: false,
};
}
const tag = token.tags?.find(
(item) =>
item.end + item.comment?.length + 1 >= position &&
item.pos <= position
);
const isExpectTag =
tag && tag.comment && tag.tagName.escapedText === "expect";
if (isExpectTag) {
const hasNotKeyword = tag.comment?.includes("not");
const fnKeyword =
EXPECT_KEYWORDS.find((keyword) => tag.comment?.includes(keyword)) ||
"";
const keywordPosition =
tag.end + tag.comment.indexOf(fnKeyword) + fnKeyword.length;
original.entries = [
...original.entries,
...[
...(hasNotKeyword || fnKeyword ? [] : ["not"]),
...(fnKeyword && keywordPosition !== position
? []
: EXPECT_KEYWORDS),
].map((name) => ({
kind: ScriptElementKind.functionElement,
name,
kindModifiers: "",
sortText: "0",
})),
];
}
}
return original;
}
public getQuickInfoAtPosition(
delegate: ts.LanguageService["getQuickInfoAtPosition"],
fileName: string,
position: number
): ReturnType<ts.LanguageService["getQuickInfoAtPosition"]> {
const original = delegate(fileName, position);
// Remove expect tags when user hover function name
if (original) {
original.tags = original.tags?.filter((item) => item.name !== "expect");
}
return original;
}
public getCompletionEntryDetails(
delegate: ts.LanguageService["getCompletionEntryDetails"],
fileName: string,
position: number,
entryName: string,
formatOptions: ts.FormatCodeOptions | ts.FormatCodeSettings,
source: string,
preferences: ts.UserPreferences
): ReturnType<ts.LanguageService["getCompletionEntryDetails"]> {
const original = delegate(
fileName,
position,
entryName,
formatOptions,
source,
preferences
);
// Remove expect tags for autocomplete popup
if (original) {
original.tags = original.tags?.filter((item) => item.name !== "expect");
}
return original;
}
public getSignatureHelpItems(
delegate: ts.LanguageService["getSignatureHelpItems"],
fileName: string,
position: number,
options: ts.SignatureHelpItemsOptions
): ReturnType<ts.LanguageService["getSignatureHelpItems"]> {
const original = delegate(fileName, position, options);
// Remove expect tags for autocomplete popup
if (original) {
original.items = original.items.map((item) => ({
...item,
// Remove expect tags from signature tooltip
tags: item.tags?.filter((item) => item.name !== "expect"),
}));
}
return original;
}
private transformErrorsToDiagnostics(
sourceFile: ts.SourceFile
): ts.Diagnostic[] {
return this.messageBag.messages.map((item) => ({
category: ts.DiagnosticCategory.Error,
file: sourceFile,
messageText: item.content,
start: item.pos,
length: item.end - item.pos - 1,
code: TS_LANGSERVICE_EXPECT_DIAGNOSTIC_ERROR_CODE,
}));
}
}
================================================
FILE: src/consts.ts
================================================
export const TS_LANGSERVICE_EXPECT_DIAGNOSTIC_ERROR_CODE = 50555;
export const EXPECT_KEYWORDS = [
"toBeDefined",
"toBe",
"toBeCloseTo",
"toBeFalsy",
"toBeGreaterThan",
"toBeGreaterThanOrEqual",
"toBeLessThan",
"toBeLessThanOrEqual",
"toBeNaN",
"toBeNull",
"toBeTruthy",
"toBeUndefined",
"toContain",
"toContainEqual",
"toEqual",
"toHaveLength",
"toHaveProperty",
"toMatchObject",
"toStrictEqual",
"toThrow",
];
================================================
FILE: src/get-expect-tag.ts
================================================
import ts from "typescript";
export function isJSDocExpectTag(tag: ts.JSDocTag): tag is ts.JSDocTag {
return tag.tagName.escapedText === "expect";
}
export function getJSDocExpectTags(node: ts.Node): readonly ts.JSDocTag[] {
return ts.getAllJSDocTags(node, isJSDocExpectTag);
}
================================================
FILE: src/get-temporary-file.ts
================================================
import ts from "typescript";
import { writeFileSync } from "fs";
import tmp from "tmp";
tmp.setGracefulCleanup();
function getTemporaryFile(node: ts.FunctionDeclaration) {
const sourceFile = node.getSourceFile();
const tempFile = tmp.fileSync({ postfix: ".ts" });
const filepath = tempFile.name.split(".").slice(0, -1).join(".");
writeFileSync(tempFile.name, sourceFile.getFullText());
const fileModule = require(filepath);
return fileModule;
}
export default getTemporaryFile;
================================================
FILE: src/index.ts
================================================
import { pluginModuleFactory } from "./plugin-module-factory";
export = pluginModuleFactory;
================================================
FILE: src/language-service-proxy-builder.ts
================================================
import ts from "typescript/lib/tsserverlibrary";
export type LanguageServiceMethodWrapper<K extends keyof ts.LanguageService> = (
delegate: ts.LanguageService[K],
info?: ts.server.PluginCreateInfo
) => ts.LanguageService[K];
export class LanguageServiceProxyBuilder {
private readonly wrappers: any[] = [];
private readonly info: ts.server.PluginCreateInfo;
public constructor(info: ts.server.PluginCreateInfo) {
this.info = info;
}
public wrap<
K extends keyof ts.LanguageService,
Q extends LanguageServiceMethodWrapper<K>
>(name: K, wrapper: Q) {
this.wrappers.push({ name, wrapper });
return this;
}
public build(): ts.LanguageService {
const ret = this.info.languageService;
this.wrappers.forEach(({ name, wrapper }) => {
(ret as any)[name] = wrapper(
this.info.languageService[name as keyof ts.LanguageService],
this.info
);
});
return ret;
}
}
================================================
FILE: src/message-bag.ts
================================================
export type Message = {
pos: number;
end: number;
content: string;
};
export class MessageBag {
messages: Message[] = [];
clear() {
this.messages = [];
}
add(message: Message) {
this.messages = [...this.messages, message];
}
}
================================================
FILE: src/parse-comment.ts
================================================
import { Matchers } from "expect";
const exp = /^(\[.+\])\s{1}((not\.?)?(?:\w+))[\s{1}]?(.+)?/;
function parseComment(comment: string) {
if (!comment) return;
const match = comment.match(exp);
if (!match) return;
const [, params, method, , result] = match;
const matcher = (method as unknown) as keyof Pick<Matchers<any>, "toEqual">;
const isUndefined = result === undefined || result === "undefined";
return {
params: JSON.parse(params),
matcher,
result: isUndefined ? [undefined] : JSON.parse(`[${result}]`),
};
}
export default parseComment;
================================================
FILE: src/plugin-module-factory.ts
================================================
import typescript from "typescript/lib/tsserverlibrary";
import { LanguageServiceProxyBuilder } from "./language-service-proxy-builder";
import { Adapter } from "./adapter";
// TODO: Use provided typescript
const create = (ts: typeof typescript) => (
info: ts.server.PluginCreateInfo
): ts.LanguageService => {
const { languageService, project } = info;
const logger = (msg: string) =>
project.projectService.logger.info(`[typescript-jest-service] ${msg}`);
const getProgram = () => {
const program = languageService.getProgram();
if (!program) throw new Error();
return program;
};
const adapter = new Adapter({
logger,
getSourceFile(fileName: string) {
return getProgram().getSourceFile(fileName);
},
});
const proxy = new LanguageServiceProxyBuilder(info)
.wrap("getSemanticDiagnostics", (delegate) =>
adapter.getSemanticDiagnostics.bind(adapter, delegate)
)
.wrap("getQuickInfoAtPosition", (delegate) =>
adapter.getQuickInfoAtPosition.bind(adapter, delegate)
)
.wrap("getCompletionEntryDetails", (delegate) =>
adapter.getCompletionEntryDetails.bind(adapter, delegate)
)
.wrap("getSignatureHelpItems", (delegate) =>
adapter.getSignatureHelpItems.bind(adapter, delegate)
)
.wrap("getCompletionsAtPosition", (delegate) =>
adapter.getCompletionsAtPosition.bind(adapter, delegate)
)
.build();
return proxy;
};
type FactoryProps = {
typescript: typeof typescript;
};
export const pluginModuleFactory: typescript.server.PluginModuleFactory = ({
typescript,
}: FactoryProps) => ({
create: create(typescript),
});
================================================
FILE: src/visit.ts
================================================
import ts from "typescript";
import expect from "expect";
import parseComment from "./parse-comment";
import getTemporaryFile from "./get-temporary-file";
import { getJSDocExpectTags } from "./get-expect-tag";
import { MessageBag } from "./message-bag";
export default (node: ts.Node, messageBag: MessageBag) => {
let defaultExport: ts.Identifier;
let namedExports: ts.Identifier[] = [];
try {
// Get default export
node.forEachChild((node) => {
if (ts.isExportAssignment(node) && ts.isIdentifier(node.expression)) {
defaultExport = node.expression;
}
});
// Get named exports
node.forEachChild((node) => {
if (ts.isExportDeclaration(node)) {
node.exportClause.forEachChild((item) => {
if (ts.isExportSpecifier(item)) {
namedExports = [...namedExports, item.name];
}
});
}
});
node.forEachChild((node) => {
const isTopLevel = ts.isSourceFile(node.parent);
if (ts.isFunctionDeclaration(node) && isTopLevel) {
if (hasExportModifier(node) || hasNamedExport(namedExports, node)) {
executeTest(node, messageBag);
}
if (isDefaultExport(defaultExport, node)) {
executeTest(node, messageBag, {
defaultExport: true,
});
}
}
});
} catch (err) {}
};
function hasNamedExport(
namedExports: ts.Identifier[],
node: ts.FunctionDeclaration
) {
return namedExports.find(
(item) => item.escapedText === node.name.escapedText
);
}
function isDefaultExport(
defaultExport: ts.Identifier,
node: ts.FunctionDeclaration
) {
return defaultExport && node.name.escapedText === defaultExport.escapedText;
}
function hasExportModifier(node: ts.FunctionDeclaration) {
return node.modifiers?.some(
(item) => item.kind === ts.SyntaxKind.ExportKeyword
);
}
function executeTest(
node: ts.FunctionDeclaration,
messageBag: MessageBag,
options: {
defaultExport?: boolean;
} = {}
) {
const expectTags = getJSDocExpectTags(node);
try {
var fileModule = getTemporaryFile(node);
} catch (err) {
if (err.diagnosticText) {
const [, pos, end] = err.diagnosticText.match(/\((\d+),(\d+)\)/);
messageBag.add({
pos,
end,
content: err.diagnosticText,
});
}
}
if (!fileModule) {
return;
}
for (const tag of expectTags) {
try {
const comment = parseComment(tag.comment);
if (!comment) continue;
const { matcher, params, result } = comment;
const functionName = options.defaultExport ? "default" : node.name.text;
const call = matcher
.split(".")
.reduce(
(prev, current) => prev[current],
expect(fileModule[functionName](...params))
);
if (typeof call === "function") {
call(...result);
}
} catch (err) {
messageBag.add({
pos: tag.pos,
end: tag.end,
content: err.message.replace(/\n\s*\n/g, "\n"),
});
}
}
}
================================================
FILE: tsconfig.json
================================================
{
"compilerOptions": {
"target": "ES2015",
"outDir": "lib",
"module": "CommonJS",
"moduleResolution": "node",
"esModuleInterop": true
}
}
gitextract_2hbh9kz3/ ├── .github/ │ └── workflows/ │ └── main.yml ├── .gitignore ├── .vscode/ │ └── settings.json ├── LICENSE ├── README.md ├── package.json ├── src/ │ ├── adapter.ts │ ├── consts.ts │ ├── get-expect-tag.ts │ ├── get-temporary-file.ts │ ├── index.ts │ ├── language-service-proxy-builder.ts │ ├── message-bag.ts │ ├── parse-comment.ts │ ├── plugin-module-factory.ts │ └── visit.ts └── tsconfig.json
SYMBOL INDEX (30 symbols across 9 files)
FILE: src/adapter.ts
type ESLintAdapterOptions (line 17) | type ESLintAdapterOptions = {
class Adapter (line 23) | class Adapter {
method constructor (line 30) | public constructor({ logger, getSourceFile }: ESLintAdapterOptions) {
method getSemanticDiagnostics (line 36) | public getSemanticDiagnostics(
method getCompletionsAtPosition (line 57) | public getCompletionsAtPosition(
method getQuickInfoAtPosition (line 126) | public getQuickInfoAtPosition(
method getCompletionEntryDetails (line 139) | public getCompletionEntryDetails(
method getSignatureHelpItems (line 163) | public getSignatureHelpItems(
method transformErrorsToDiagnostics (line 181) | private transformErrorsToDiagnostics(
FILE: src/consts.ts
constant TS_LANGSERVICE_EXPECT_DIAGNOSTIC_ERROR_CODE (line 1) | const TS_LANGSERVICE_EXPECT_DIAGNOSTIC_ERROR_CODE = 50555;
constant EXPECT_KEYWORDS (line 2) | const EXPECT_KEYWORDS = [
FILE: src/get-expect-tag.ts
function isJSDocExpectTag (line 3) | function isJSDocExpectTag(tag: ts.JSDocTag): tag is ts.JSDocTag {
function getJSDocExpectTags (line 7) | function getJSDocExpectTags(node: ts.Node): readonly ts.JSDocTag[] {
FILE: src/get-temporary-file.ts
function getTemporaryFile (line 7) | function getTemporaryFile(node: ts.FunctionDeclaration) {
FILE: src/language-service-proxy-builder.ts
type LanguageServiceMethodWrapper (line 3) | type LanguageServiceMethodWrapper<K extends keyof ts.LanguageService> = (
class LanguageServiceProxyBuilder (line 8) | class LanguageServiceProxyBuilder {
method constructor (line 12) | public constructor(info: ts.server.PluginCreateInfo) {
method wrap (line 16) | public wrap<
method build (line 24) | public build(): ts.LanguageService {
FILE: src/message-bag.ts
type Message (line 1) | type Message = {
class MessageBag (line 7) | class MessageBag {
method clear (line 10) | clear() {
method add (line 14) | add(message: Message) {
FILE: src/parse-comment.ts
function parseComment (line 5) | function parseComment(comment: string) {
FILE: src/plugin-module-factory.ts
method getSourceFile (line 19) | getSourceFile(fileName: string) {
type FactoryProps (line 43) | type FactoryProps = {
FILE: src/visit.ts
function hasNamedExport (line 48) | function hasNamedExport(
function isDefaultExport (line 57) | function isDefaultExport(
function hasExportModifier (line 64) | function hasExportModifier(node: ts.FunctionDeclaration) {
function executeTest (line 70) | function executeTest(
Condensed preview — 17 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (22K chars).
[
{
"path": ".github/workflows/main.yml",
"chars": 653,
"preview": "name: CI\non: [push]\njobs:\n build:\n runs-on: ubuntu-latest\n\n steps:\n - name: Begin CI...\n uses: action"
},
{
"path": ".gitignore",
"chars": 23,
"preview": "node_modules\nlib\n*.log\n"
},
{
"path": ".vscode/settings.json",
"chars": 88,
"preview": "{\n \"editor.formatOnSave\": true,\n \"typescript.tsdk\": \"node_modules\\\\typescript\\\\lib\"\n}\n"
},
{
"path": "LICENSE",
"chars": 1073,
"preview": "MIT License\n\nCopyright (c) 2020 Kasper Mikiewicz\n\nPermission is hereby granted, free of charge, to any person obtaining "
},
{
"path": "README.md",
"chars": 3219,
"preview": "<h1 align=\"center\">Typescript Expect Plugin</h1>\n<p align=\"center\">\n <img alt=\"npm\" src=\"https://img.shields.io/npm/v/"
},
{
"path": "package.json",
"chars": 1070,
"preview": "{\n \"name\": \"typescript-expect-plugin\",\n \"description\": \"Be lazy, write simple tests in comments\",\n \"version\": \"0.3.1\""
},
{
"path": "src/adapter.ts",
"chars": 5691,
"preview": "import ts, { ScriptElementKind } from \"typescript\";\nimport bts from \"byots\";\nimport { register } from \"ts-node\";\nimport "
},
{
"path": "src/consts.ts",
"chars": 452,
"preview": "export const TS_LANGSERVICE_EXPECT_DIAGNOSTIC_ERROR_CODE = 50555;\nexport const EXPECT_KEYWORDS = [\n \"toBeDefined\",\n \"t"
},
{
"path": "src/get-expect-tag.ts",
"chars": 284,
"preview": "import ts from \"typescript\";\n\nexport function isJSDocExpectTag(tag: ts.JSDocTag): tag is ts.JSDocTag {\n return tag.tagN"
},
{
"path": "src/get-temporary-file.ts",
"chars": 494,
"preview": "import ts from \"typescript\";\nimport { writeFileSync } from \"fs\";\nimport tmp from \"tmp\";\n\ntmp.setGracefulCleanup();\n\nfunc"
},
{
"path": "src/index.ts",
"chars": 94,
"preview": "import { pluginModuleFactory } from \"./plugin-module-factory\";\n\nexport = pluginModuleFactory;\n"
},
{
"path": "src/language-service-proxy-builder.ts",
"chars": 942,
"preview": "import ts from \"typescript/lib/tsserverlibrary\";\n\nexport type LanguageServiceMethodWrapper<K extends keyof ts.LanguageSe"
},
{
"path": "src/message-bag.ts",
"chars": 254,
"preview": "export type Message = {\n pos: number;\n end: number;\n content: string;\n};\n\nexport class MessageBag {\n messages: Messa"
},
{
"path": "src/parse-comment.ts",
"chars": 577,
"preview": "import { Matchers } from \"expect\";\n\nconst exp = /^(\\[.+\\])\\s{1}((not\\.?)?(?:\\w+))[\\s{1}]?(.+)?/;\n\nfunction parseComment("
},
{
"path": "src/plugin-module-factory.ts",
"chars": 1644,
"preview": "import typescript from \"typescript/lib/tsserverlibrary\";\nimport { LanguageServiceProxyBuilder } from \"./language-service"
},
{
"path": "src/visit.ts",
"chars": 3036,
"preview": "import ts from \"typescript\";\nimport expect from \"expect\";\nimport parseComment from \"./parse-comment\";\nimport getTemporar"
},
{
"path": "tsconfig.json",
"chars": 162,
"preview": "{\n \"compilerOptions\": {\n \"target\": \"ES2015\",\n \"outDir\": \"lib\",\n \"module\": \"CommonJS\",\n \"moduleResolution\": "
}
]
About this extraction
This page contains the full source code of the Idered/typescript-expect-plugin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 17 files (19.3 KB), approximately 5.4k tokens, and a symbol index with 30 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.