@codechecks/type-coverage-watcher
Advanced tools
+1
-1
| import { Options } from "./types"; | ||
| export declare function typeCoverageWatcher(_options: Options): Promise<void>; | ||
| export declare function typeCoverageWatcher(_options?: Options): Promise<void>; | ||
| export default typeCoverageWatcher; |
+1
-1
@@ -7,3 +7,3 @@ "use strict"; | ||
| const formatters_1 = require("./formatters"); | ||
| async function typeCoverageWatcher(_options) { | ||
| async function typeCoverageWatcher(_options = {}) { | ||
| const options = normalizeOptions(_options); | ||
@@ -10,0 +10,0 @@ const _typeCoverage = await type_coverage_core_1.lint(options.tsconfigPath, { |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,+CAAkE;AAClE,2DAAiE;AAEjE,mCAAiC;AACjC,6CAAsD;AAE/C,KAAK,UAAU,mBAAmB,CAAC,QAAiB;IACzD,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC3C,MAAM,aAAa,GAAG,MAAM,yBAAmB,CAAC,OAAO,CAAC,YAAY,EAAE;QACpE,KAAK,EAAE,KAAK;QACZ,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,MAAM,EAAE,QAAQ,CAAC,MAAM;KACxB,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;IAC1D,MAAM,mBAAU,CAAC,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IAE/D,IAAI,CAAC,mBAAU,CAAC,IAAI,EAAE,EAAE;QACtB,OAAO;KACR;IAED,MAAM,gBAAgB,GAAG,MAAM,mBAAU,CAAC,QAAQ,CAAuB,OAAO,CAAC,YAAY,CAAC,CAAC;IAE/F,MAAM,MAAM,GAAG,SAAS,CAAC,YAAY,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAElE,MAAM,mBAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAClC,CAAC;AApBD,kDAoBC;AAED,kBAAe,mBAAmB,CAAC;AAEnC,SAAS,SAAS,CAChB,wBAA8C,EAC9C,wBAA0D,EAC1D,OAA0B;IAE1B,MAAM,gBAAgB,GAAG,CAAC,wBAAwB,CAAC,YAAY,GAAG,wBAAwB,CAAC,YAAY,CAAC,GAAG,GAAG,CAAC;IAC/G,MAAM,gBAAgB,GAAG,wBAAwB;QAC/C,CAAC,CAAC,CAAC,wBAAwB,CAAC,YAAY,GAAG,wBAAwB,CAAC,YAAY,CAAC,GAAG,GAAG;QACvF,CAAC,CAAC,CAAC,CAAC;IACN,MAAM,YAAY,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;IAEzD,MAAM,iBAAiB,GAAG,OAAO,CAC/B,wBAAwB,CAAC,iBAAiB,EAC1C,wBAAwB,CAAC,CAAC,CAAC,wBAAwB,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAC3E,CAAC;IAEF,MAAM,gBAAgB,GAAG,mCAAsB,CAAC;QAC9C,gBAAgB,EAAE,YAAY;QAC9B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,oBAAoB,EAAE,gBAAgB;QACtC,iBAAiB,EAAE,iBAAiB,CAAC,MAAM;KAC5C,CAAC,CAAC;IAEH,IAAI,eAAe,GAAG,wBAAwB,iBAAiB,CAAC,MAAM,EAAE,CAAC;IACzE,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE;QAChC,eAAe,IAAI;;;;EAIrB,iBAAiB;aAChB,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;aACb,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,MAAM,IAAI,CAAC;aACtE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;KACb;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,KAAK,SAAS,IAAI,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAE3G,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM;QACN,gBAAgB;QAChB,eAAe;KAChB,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,WAAyB,EAAE,WAAyB;IACnE,MAAM,qBAAqB,GAAG,gBAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACpE,MAAM,UAAU,GAAiB,EAAE,CAAC;IAEpC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE;QACpC,+GAA+G;QAC/G,MAAM,eAAe,GACnB,CAAC,qBAAqB,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QAE5G,IAAI,CAAC,eAAe,EAAE;YACpB,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SAC7B;KACF;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,qBAAqB,CAAC,eAAsC;IACnE,OAAO;QACL,YAAY,EAAE,eAAe,CAAC,YAAY;QAC1C,YAAY,EAAE,eAAe,CAAC,UAAU;QACxC,iBAAiB,EAAE,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAChD,QAAQ,EAAE,CAAC,CAAC,IAAI;YAChB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,MAAM,EAAE,CAAC,CAAC,IAAI;SACf,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAmB,EAAE;IAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,eAAe,CAAC;IAC7C,OAAO;QACL,IAAI;QACJ,YAAY,EAAE,OAAO,CAAC,IAAI,IAAI,eAAe;QAC7C,YAAY,EAAE,iBAAiB,IAAI,EAAE;QACrC,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC;AACJ,CAAC"} | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} |
+4
-1
@@ -17,3 +17,3 @@ { | ||
| "author": "Chris Kaczor <chris@kaczor.io>", | ||
| "version": "0.1.2", | ||
| "version": "0.1.3", | ||
| "main": "lib/index.js", | ||
@@ -60,2 +60,5 @@ "types": "lib/index.d.ts", | ||
| }, | ||
| "files": [ | ||
| "lib/**/*" | ||
| ], | ||
| "publishConfig": { | ||
@@ -62,0 +65,0 @@ "access": "public" |
| version: 2 | ||
| jobs: | ||
| build: | ||
| docker: | ||
| - image: circleci/node:10.13.0 | ||
| working_directory: /home/circleci/app | ||
| steps: | ||
| - checkout | ||
| - restore_cache: | ||
| key: v1-dep-{{ checksum "yarn.lock" }} | ||
| - run: | ||
| name: Install deps | ||
| command: yarn install --frozen-lockfile | ||
| - save_cache: | ||
| paths: | ||
| - ./node_modules | ||
| - ~/.cache | ||
| key: v1-dep-{{ checksum "yarn.lock" }} | ||
| - run: | ||
| name: Run tests | ||
| command: yarn test |
Sorry, the diff of this file is not supported yet
| { | ||
| "printWidth": 120, | ||
| "tabWidth": 2, | ||
| "semi": true, | ||
| "singleQuote": false, | ||
| "trailingComma": "all" | ||
| } |
| { | ||
| // Use IntelliSense to learn about possible attributes. | ||
| // Hover to view descriptions of existing attributes. | ||
| // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||
| "version": "0.2.0", | ||
| "configurations": [ | ||
| { | ||
| "type": "node", | ||
| "request": "launch", | ||
| "name": "test", | ||
| "program": "${workspaceFolder}/node_modules/.bin/jest" | ||
| }, | ||
| { | ||
| "type": "node", | ||
| "request": "launch", | ||
| "name": "test (update snapshots)", | ||
| "program": "${workspaceFolder}/node_modules/.bin/jest", | ||
| "args": ["-u"] | ||
| } | ||
| ] | ||
| } |
| # Contributing | ||
| All contributions are welcomed. | ||
| Do you have an idea for improving this check? Please, first submit a github issue and describe your | ||
| proposal. | ||
| When you're done with your changes use `yarn test:fix` to run `prettier` to reformat code, `tslint` | ||
| in fix mode, `tsc` to make sure that there are no compilation errors, and unit tests. | ||
| Thanks! 🙏🏻 |
| module.exports = { | ||
| roots: ["<rootDir>/src"], | ||
| transform: { | ||
| "^.+\\.tsx?$": "ts-jest", | ||
| }, | ||
| testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$", | ||
| moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], | ||
| }; |
Sorry, the diff of this file is not supported yet
| import * as CC from "@codechecks/client"; | ||
| import { join } from "path"; | ||
| export const codechecks: Partial<typeof CC.codechecks> = { | ||
| report: jest.fn(), | ||
| success: jest.fn(), | ||
| failure: jest.fn(), | ||
| getValue: jest.fn(), | ||
| saveValue: jest.fn(), | ||
| getDirectory: jest.fn(), | ||
| saveDirectory: jest.fn(), | ||
| isPr: jest.fn(), | ||
| context: { | ||
| workspaceRoot: join(__dirname, "..", ".."), | ||
| } as any, | ||
| }; |
| import * as TypeCoverage from "type-coverage-core"; | ||
| export const lint: typeof TypeCoverage.lint = jest.fn(); |
| import { formatShortDescription } from "../formatters"; | ||
| describe("formatters > formatShortDescription", () => { | ||
| it("should work", () => { | ||
| const actual = formatShortDescription({ coverageDiffPerc: 1.4, headTypeCoveragePerc: 90.2, newUntypedSymbols: 1 }); | ||
| expect(actual).toMatchInlineSnapshot(`"Change: +1.40% Total: 90.20% New untyped symbols: 1"`); | ||
| }); | ||
| it("should work with atLeast", () => { | ||
| const actual = formatShortDescription({ | ||
| coverageDiffPerc: 1.4, | ||
| headTypeCoveragePerc: 90.2, | ||
| newUntypedSymbols: 1, | ||
| atLeast: 90, | ||
| }); | ||
| expect(actual).toMatchInlineSnapshot(`"Change: +1.40% Total: 90.20% (min. 90.00%) New untyped symbols: 1"`); | ||
| }); | ||
| }); |
| import { typeCoverageWatcher } from "../index"; | ||
| import { lint } from "type-coverage-core"; | ||
| import { codechecks } from "@codechecks/client"; | ||
| import { TypeCoverageArtifact, RawTypeCoverageReport } from "../types"; | ||
| type Mocked<T> = { [k in keyof T]: jest.Mock<T[k]> }; | ||
| describe("type-coverage", () => { | ||
| const codechecksMock = require("../__mocks__/@codechecks/client").codechecks as Mocked<typeof codechecks>; | ||
| const typeCoverageMock = require("../__mocks__/type-coverage-core").lint as jest.Mock<typeof lint>; | ||
| beforeEach(() => jest.resetAllMocks()); | ||
| it("should work not in PR context", async () => { | ||
| codechecksMock.isPr.mockReturnValue(false); | ||
| typeCoverageMock.mockReturnValue({ | ||
| correctCount: 2, | ||
| totalCount: 2, | ||
| anys: [], | ||
| program: undefined as any, | ||
| }); | ||
| await typeCoverageWatcher({ tsconfigPath: "./tsconfig.json" }); | ||
| expect(codechecks.report).toBeCalledTimes(0); | ||
| expect(codechecks.saveValue).toMatchInlineSnapshot(` | ||
| [MockFunction] { | ||
| "calls": Array [ | ||
| Array [ | ||
| "type-coverage:Type Coverage", | ||
| Object { | ||
| "allUntypedSymbols": Array [], | ||
| "totalSymbols": 2, | ||
| "typedSymbols": 2, | ||
| }, | ||
| ], | ||
| ], | ||
| "results": Array [ | ||
| Object { | ||
| "isThrow": false, | ||
| "value": undefined, | ||
| }, | ||
| ], | ||
| } | ||
| `); | ||
| }); | ||
| it("should work in PR context", async () => { | ||
| codechecksMock.isPr.mockReturnValue(true); | ||
| codechecksMock.getValue.mockReturnValue({ | ||
| typedSymbols: 2, | ||
| totalSymbols: 4, | ||
| allUntypedSymbols: [ | ||
| { filename: "index.ts", character: 1, line: 10, symbol: "app" }, | ||
| { filename: "index.ts", character: 1, line: 15, symbol: "res" }, | ||
| { filename: "index.ts", character: 2, line: 15, symbol: "key" }, // here we test that plugin doesnt care about exact place of a symbol, just it's name | ||
| ], | ||
| } as TypeCoverageArtifact); | ||
| typeCoverageMock.mockReturnValue({ | ||
| correctCount: 3, | ||
| totalCount: 4, | ||
| anys: [ | ||
| { file: "index.ts", character: 1, line: 15, text: "res" }, | ||
| { file: "index.ts", character: 3, line: 16, text: "key" }, | ||
| ], | ||
| program: undefined as any, | ||
| } as RawTypeCoverageReport); | ||
| await typeCoverageWatcher({ tsconfigPath: "./tsconfig.json" }); | ||
| expect(codechecks.report).toMatchInlineSnapshot(` | ||
| [MockFunction] { | ||
| "calls": Array [ | ||
| Array [ | ||
| Object { | ||
| "longDescription": "New untyped symbols: 0", | ||
| "name": "Type Coverage", | ||
| "shortDescription": "Change: +25.00% Total: 75.00% New untyped symbols: 0", | ||
| "status": "success", | ||
| }, | ||
| ], | ||
| ], | ||
| "results": Array [ | ||
| Object { | ||
| "isThrow": false, | ||
| "value": undefined, | ||
| }, | ||
| ], | ||
| } | ||
| `); | ||
| }); | ||
| it("should work in PR context 2", async () => { | ||
| codechecksMock.isPr.mockReturnValue(true); | ||
| codechecksMock.getValue.mockReturnValue({ | ||
| typedSymbols: 4, | ||
| totalSymbols: 5, | ||
| allUntypedSymbols: [], | ||
| } as TypeCoverageArtifact); | ||
| typeCoverageMock.mockReturnValue({ | ||
| correctCount: 3, | ||
| totalCount: 4, | ||
| anys: [{ file: "index.ts", character: 1, line: 15, text: "res" }], | ||
| program: undefined as any, | ||
| } as RawTypeCoverageReport); | ||
| await typeCoverageWatcher({ tsconfigPath: "./tsconfig.json" }); | ||
| expect(codechecks.report).toMatchInlineSnapshot(` | ||
| [MockFunction] { | ||
| "calls": Array [ | ||
| Array [ | ||
| Object { | ||
| "longDescription": "New untyped symbols: 1 | ||
| | File | line:character | Symbol | | ||
| |:-----:|:-----:|:-----:| | ||
| | index.ts | 15:1 | res |", | ||
| "name": "Type Coverage", | ||
| "shortDescription": "Change: -5.00% Total: 75.00% New untyped symbols: 1", | ||
| "status": "success", | ||
| }, | ||
| ], | ||
| ], | ||
| "results": Array [ | ||
| Object { | ||
| "isThrow": false, | ||
| "value": undefined, | ||
| }, | ||
| ], | ||
| } | ||
| `); | ||
| }); | ||
| it("should work in PR context without baseline", async () => { | ||
| codechecksMock.isPr.mockReturnValue(true); | ||
| typeCoverageMock.mockReturnValue({ | ||
| correctCount: 2, | ||
| totalCount: 2, | ||
| anys: [], | ||
| program: undefined as any, | ||
| }); | ||
| await typeCoverageWatcher({ tsconfigPath: "./tsconfig.json" }); | ||
| expect(codechecks.report).toMatchInlineSnapshot(` | ||
| [MockFunction] { | ||
| "calls": Array [ | ||
| Array [ | ||
| Object { | ||
| "longDescription": "New untyped symbols: 0", | ||
| "name": "Type Coverage", | ||
| "shortDescription": "Change: +100.00% Total: 100.00% New untyped symbols: 0", | ||
| "status": "success", | ||
| }, | ||
| ], | ||
| ], | ||
| "results": Array [ | ||
| Object { | ||
| "isThrow": false, | ||
| "value": undefined, | ||
| }, | ||
| ], | ||
| } | ||
| `); | ||
| }); | ||
| it("should handle atLeast option", async () => { | ||
| codechecksMock.isPr.mockReturnValue(true); | ||
| typeCoverageMock.mockReturnValue({ | ||
| correctCount: 4, | ||
| totalCount: 10, | ||
| anys: [], | ||
| program: undefined as any, | ||
| }); | ||
| await typeCoverageWatcher({ tsconfigPath: "./tsconfig.json", atLeast: 50 }); | ||
| expect(codechecks.report).toMatchInlineSnapshot(` | ||
| [MockFunction] { | ||
| "calls": Array [ | ||
| Array [ | ||
| Object { | ||
| "longDescription": "New untyped symbols: 0", | ||
| "name": "Type Coverage", | ||
| "shortDescription": "Change: +40.00% Total: 40.00% (min. 50.00%) New untyped symbols: 0", | ||
| "status": "failure", | ||
| }, | ||
| ], | ||
| ], | ||
| "results": Array [ | ||
| Object { | ||
| "isThrow": false, | ||
| "value": undefined, | ||
| }, | ||
| ], | ||
| } | ||
| `); | ||
| }); | ||
| }); |
| interface FormatShortDescriptionArgs { | ||
| coverageDiffPerc: number; | ||
| headTypeCoveragePerc: number; | ||
| newUntypedSymbols: number; | ||
| atLeast?: number; | ||
| } | ||
| export function formatShortDescription({ | ||
| coverageDiffPerc, | ||
| atLeast, | ||
| headTypeCoveragePerc, | ||
| newUntypedSymbols, | ||
| }: FormatShortDescriptionArgs): string { | ||
| const change = renderSign(coverageDiffPerc) + perc(coverageDiffPerc); | ||
| const limit = atLeast === undefined ? "" : ` (min. ${perc(atLeast)})`; | ||
| const total = perc(headTypeCoveragePerc); | ||
| return `Change: ${change} Total: ${total}${limit} New untyped symbols: ${newUntypedSymbols}`; | ||
| } | ||
| export function perc(n: number): string { | ||
| return n.toFixed(2) + "%"; | ||
| } | ||
| export function renderSign(value: number): string { | ||
| if (value > 0) { | ||
| return "+"; | ||
| } else { | ||
| // we dont' render signs for negative (it's part of a number xD) or 0 | ||
| return ""; | ||
| } | ||
| } |
-114
| import { codechecks, CodeChecksReport } from "@codechecks/client"; | ||
| import { lint as getTypeCoverageInfo } from "type-coverage-core"; | ||
| import { RawTypeCoverageReport, TypeCoverageArtifact, Options, SymbolInfo, NormalizedOptions } from "./types"; | ||
| import { groupBy } from "lodash"; | ||
| import { formatShortDescription } from "./formatters"; | ||
| export async function typeCoverageWatcher(_options: Options): Promise<void> { | ||
| const options = normalizeOptions(_options); | ||
| const _typeCoverage = await getTypeCoverageInfo(options.tsconfigPath, { | ||
| debug: false, | ||
| ignoreCatch: _options.ignoreCatch, | ||
| ignoreFiles: _options.ignoreFiles, | ||
| strict: _options.strict, | ||
| }); | ||
| const typeCoverage = normalizeTypeCoverage(_typeCoverage); | ||
| await codechecks.saveValue(options.artifactName, typeCoverage); | ||
| if (!codechecks.isPr()) { | ||
| return; | ||
| } | ||
| const baseTypeCoverage = await codechecks.getValue<TypeCoverageArtifact>(options.artifactName); | ||
| const report = getReport(typeCoverage, baseTypeCoverage, options); | ||
| await codechecks.report(report); | ||
| } | ||
| export default typeCoverageWatcher; | ||
| function getReport( | ||
| headTypeCoverageArtifact: TypeCoverageArtifact, | ||
| baseTypeCoverageArtifact: TypeCoverageArtifact | undefined, | ||
| options: NormalizedOptions, | ||
| ): CodeChecksReport { | ||
| const headTypeCoverage = (headTypeCoverageArtifact.typedSymbols / headTypeCoverageArtifact.totalSymbols) * 100; | ||
| const baseTypeCoverage = baseTypeCoverageArtifact | ||
| ? (baseTypeCoverageArtifact.typedSymbols / baseTypeCoverageArtifact.totalSymbols) * 100 | ||
| : 0; | ||
| const coverageDiff = headTypeCoverage - baseTypeCoverage; | ||
| const newUntypedSymbols = findNew( | ||
| headTypeCoverageArtifact.allUntypedSymbols, | ||
| baseTypeCoverageArtifact ? baseTypeCoverageArtifact.allUntypedSymbols : [], | ||
| ); | ||
| const shortDescription = formatShortDescription({ | ||
| coverageDiffPerc: coverageDiff, | ||
| atLeast: options.atLeast, | ||
| headTypeCoveragePerc: headTypeCoverage, | ||
| newUntypedSymbols: newUntypedSymbols.length, | ||
| }); | ||
| let longDescription = `New untyped symbols: ${newUntypedSymbols.length}`; | ||
| if (newUntypedSymbols.length > 0) { | ||
| longDescription += ` | ||
| | File | line:character | Symbol | | ||
| |:-----:|:-----:|:-----:| | ||
| ${newUntypedSymbols | ||
| .slice(0, 100) | ||
| .map(s => `| ${s.filename} | ${s.line}:${s.character} | ${s.symbol} |`) | ||
| .join("\n")}`; | ||
| } | ||
| const status = options.atLeast === undefined || headTypeCoverage > options.atLeast ? "success" : "failure"; | ||
| return { | ||
| name: options.name, | ||
| status, | ||
| shortDescription, | ||
| longDescription, | ||
| }; | ||
| } | ||
| function findNew(headSymbols: SymbolInfo[], baseSymbols: SymbolInfo[]): SymbolInfo[] { | ||
| const baseSymbolsByFilename = groupBy(baseSymbols, s => s.filename); | ||
| const newSymbols: SymbolInfo[] = []; | ||
| for (const headSymbol of headSymbols) { | ||
| // we assess if symbols are the same only by looking at filename and symbol name (we ignore line and character) | ||
| const baseSymbolMatch = | ||
| (baseSymbolsByFilename[headSymbol.filename] || []).filter(s => s.symbol === headSymbol.symbol).length > 0; | ||
| if (!baseSymbolMatch) { | ||
| newSymbols.push(headSymbol); | ||
| } | ||
| } | ||
| return newSymbols; | ||
| } | ||
| function normalizeTypeCoverage(rawTypeCoverage: RawTypeCoverageReport): TypeCoverageArtifact { | ||
| return { | ||
| typedSymbols: rawTypeCoverage.correctCount, | ||
| totalSymbols: rawTypeCoverage.totalCount, | ||
| allUntypedSymbols: rawTypeCoverage.anys.map(a => ({ | ||
| filename: a.file, | ||
| line: a.line, | ||
| character: a.character, | ||
| symbol: a.text, | ||
| })), | ||
| }; | ||
| } | ||
| function normalizeOptions(options: Options = {}): NormalizedOptions { | ||
| const name = options.name || "Type Coverage"; | ||
| return { | ||
| name, | ||
| tsconfigPath: options.name || "tsconfig.json", | ||
| artifactName: `type-coverage:${name}`, | ||
| atLeast: options.atLeast, | ||
| }; | ||
| } |
-36
| import { AnyInfo } from "type-coverage-core"; | ||
| export interface Options { | ||
| tsconfigPath?: string; | ||
| name?: string; | ||
| ignoreFiles?: string[]; | ||
| ignoreCatch?: boolean; | ||
| atLeast?: number; | ||
| strict?: boolean; | ||
| } | ||
| export interface NormalizedOptions { | ||
| tsconfigPath: string; | ||
| name: string; | ||
| artifactName: string; | ||
| atLeast?: number; | ||
| } | ||
| export interface TypeCoverageArtifact { | ||
| typedSymbols: number; | ||
| totalSymbols: number; | ||
| allUntypedSymbols: SymbolInfo[]; | ||
| } | ||
| export interface SymbolInfo { | ||
| filename: string; | ||
| line: number; | ||
| character: number; | ||
| symbol: string; | ||
| } | ||
| export interface RawTypeCoverageReport { | ||
| correctCount: number; | ||
| totalCount: number; | ||
| anys: AnyInfo[]; | ||
| } |
| { | ||
| "compilerOptions": { | ||
| "target": "es2017", | ||
| "module": "commonjs", | ||
| "strict": true, | ||
| "experimentalDecorators": true, | ||
| "emitDecoratorMetadata": true, | ||
| "forceConsistentCasingInFileNames": true, | ||
| "plugins": [ | ||
| { | ||
| "name": "tslint-language-service", | ||
| "configFile": "./node_modules/typestrict/tslint.js", | ||
| "alwaysShowRuleFailuresAsWarnings": true | ||
| } | ||
| ], | ||
| "lib": ["es2015", "esnext.asynciterable"], | ||
| "sourceMap": true, | ||
| "declaration": true, | ||
| "outDir": "lib", | ||
| "skipLibCheck": true | ||
| }, | ||
| "include": ["src/**/*.ts"], | ||
| "exclude": ["node_modules"] | ||
| } |
-13
| { | ||
| "extends": "typestrict", | ||
| "rules": { | ||
| "no-console": true, | ||
| "no-debugger": true, | ||
| "typedef": [true, "call-signature"], | ||
| "mocha-avoid-only": true, | ||
| "interface-name": [true, "never-prefix"], | ||
| "no-commented-code": true, | ||
| "no-use-before-declare": false, | ||
| "restrict-plus-operands": false | ||
| } | ||
| } |
Sorry, the diff of this file is too big to display
27231
-91.1%25
-40.48%381
-53.19%