From 4a1f6bf4eb1a8a8a8aa0d7b77721671d9b23c8e3 Mon Sep 17 00:00:00 2001 From: Timur Seitosmanov Date: Tue, 11 Oct 2022 14:20:12 +0200 Subject: [PATCH 1/4] Nicer tsconfig. --- tests/tsconfig.json | 6 ++++++ tsconfig.json | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 tests/tsconfig.json diff --git a/tests/tsconfig.json b/tests/tsconfig.json new file mode 100644 index 0000000..f9025fd --- /dev/null +++ b/tests/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "rootDirs": ["../tests", "../src"] + } +} diff --git a/tsconfig.json b/tsconfig.json index 423a440..9d80ef1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,8 @@ "sourceMap": true /* Generates corresponding '.map' file. */, // "outFile": "./", /* Concatenate and emit output to single file. */ "outDir": "./lib" /* Redirect output structure to the directory. */, - "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, + "rootDirs": [ + "./src"] /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, // "composite": true, /* Enable project compilation */ // "removeComments": true, /* Do not emit comments to output. */ // "noEmit": true, /* Do not emit outputs. */ From 96af88001e465585d8aa3e9208a091aac8797119 Mon Sep 17 00:00:00 2001 From: Timur Seitosmanov Date: Tue, 11 Oct 2022 14:42:59 +0200 Subject: [PATCH 2/4] Script for breaking files. --- package.json | 2 +- tests/generate.ts | 131 ++++++++++++++++++++-------------------------- 2 files changed, 57 insertions(+), 76 deletions(-) diff --git a/package.json b/package.json index 60d8d81..cf97e1c 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "repository": "github:rhys-vdw/ts-auto-guard", "main": "lib/index.js", "scripts": { - "test": "cross-env NODE_ENV=test && npm run lint && npm run format:check && tape -r ts-node/register tests/**/*.ts | tap-diff", + "test": "tape -r ts-node/register tests/**/*.ts", "build": "tsc", "prepare": "npm run build", "lint": "eslint .", diff --git a/tests/generate.ts b/tests/generate.ts index f033c64..9d91707 100644 --- a/tests/generate.ts +++ b/tests/generate.ts @@ -1,15 +1,16 @@ -import test from 'tape' -import { Project } from 'ts-morph' -import { minify, MinifyOptions } from 'uglify-js' -import { IProcessOptions, processProject } from '../src' - -function createProject(): Project { - return new Project({ - skipAddingFilesFromTsConfig: true, - compilerOptions: { strict: true }, - useInMemoryFileSystem: true, - }) -} +// import test from 'tape' +// import { Project } from 'ts-morph' +import { MinifyOptions } from 'uglify-js' +import { IProcessOptions } from '../src' +import fs from 'fs' + +// function createProject(): Project { +// return new Project({ +// skipAddingFilesFromTsConfig: true, +// compilerOptions: { strict: true }, +// useInMemoryFileSystem: true, +// }) +// } interface ITestOptions { skip?: boolean @@ -19,74 +20,54 @@ interface ITestOptions { throws?: RegExp | typeof Error } -function testProcessProject( - typeDescription: string, - input: { readonly [filename: string]: string }, - output: { readonly [filename: string]: string | null }, - { skip, only, options, minifyOptions, throws }: ITestOptions = {} -) { - const fn = skip ? test.skip : only ? test.only : test - fn(typeDescription, t => { - const project = createProject() - Object.entries(input).forEach(([filePath, content]) => { - project.createSourceFile(filePath, content) - }) - project.saveSync() - - const expectedFilenames = new Set(Object.keys(output)) - - if (throws) { - t.throws(() => { - processProject(project, options) - }, throws) - t.end() - return - } +function replaceAll(str: string, match: string, replacement: string) { + return str.split(match).join(replacement) +} - t.doesNotThrow(() => { - processProject(project, options) - }) - - for (const sourceFile of project.getSourceFiles()) { - const filePath = sourceFile.getFilePath().slice(1) - const expectedRaw = output[filePath] - if (expectedRaw === undefined) { - t.fail(`unexpected file ${filePath}`) - } else if (expectedRaw === null) { - // This file is expected, but must not have been changed - expectedFilenames.delete(filePath) - const sourceText = sourceFile.getFullText() - t.equal(sourceText, input[filePath], `${filePath} should not change`) - } else { - // This is a new file - expectedFilenames.delete(filePath) - const expectedFile = project.createSourceFile( - `${filePath}.expected`, - expectedRaw - ) - let sourceText: string - if (minifyOptions !== undefined) { - const emitOutput = sourceFile.getEmitOutput() - const result = minify( - emitOutput.getOutputFiles()[0].getText(), - minifyOptions - ) - t.error(result.error, 'UglifyJS should succeed') - sourceText = result.code - } else { - expectedFile.formatText() - sourceText = sourceFile.getText() - } +const src = fs.readFileSync(__filename, 'utf-8') +const lines = src.split('\r\n') - const expectedText = expectedFile.getText() - t.equal(sourceText, expectedText, `${filePath} should match`) +export function testProcessProject( + typeDescription: string, + _: { readonly [filename: string]: string }, + _0: { readonly [filename: string]: string | null }, + _1: ITestOptions = {} +) { + const name = replaceAll(replaceAll(typeDescription, ' ', '_'), '.', '') + let titleLine: number | false = false + let endLine: number | false = false + const blockLines = [] + blockLines.push("import {testProcessProject} from '../generate';") + blockLines.push('') + for (let i = 0; i < lines.length; i++) { + if (titleLine === false) { + const titleI = lines[i].indexOf(typeDescription) + if (titleI > 0) { + titleLine = i + blockLines.push(lines[i - 1]) + blockLines.push(lines[i]) + } + } else { + blockLines.push(lines[i]) + if (lines[i] === ')') { + endLine = i + break } } - for (const filePath of expectedFilenames) { - t.fail(`${filePath} not found`) + } + if (titleLine === false || endLine === false) { + console.log('skipped : ' + name) + } else { + try { + fs.writeFileSync( + __dirname + '/features/' + name + '.ts', + blockLines.join('\r\n'), + 'utf-8' + ) + } catch (e) { + console.log('skipped (due to error) : ' + name) } - t.end() - }) + } } testProcessProject( From 64900cada8c96c0157268661aaa23d00196505c4 Mon Sep 17 00:00:00 2001 From: Timur Seitosmanov Date: Tue, 11 Oct 2022 15:01:24 +0200 Subject: [PATCH 3/4] Extracted tests in separate files. --- ..._import_to_source_file_and_also_exports.ts | 34 + ..._of_the_guard_file_file_to_be_specified.ts | 34 + ..._and_unknown_work_in_interesction_types.ts | 41 + .../any_and_unknown_work_in_union_types.ts | 41 + ...f_any_callable_properties_is_a_function.ts | 40 + ...eck_if_callable_interface_is_a_function.ts | 29 + .../correctly_handles_default_export.ts | 31 + ...deals_with_unknown_type_as_it_would_any.ts | 30 + .../does_not_generate_empty_guard_files.ts | 9 + ...uardts_files_that_are_not_autogenerated.ts | 7 + ...generated_type_guards_for_arrays_of_any.ts | 28 + ...ed_type_guards_for_discriminated_unions.ts | 32 + .../generated_type_guards_for_enums.ts | 28 + ...rated_type_guards_for_intersection_type.ts | 30 + ...generated_type_guards_for_nested_arrays.ts | 39 + ...s_for_numeric_enums_in_optional_records.ts | 49 + ...cuit_are_correctly_stripped_by_UglifyJS.ts | 24 + tests/features/generates_tuples.ts | 28 + ...type_guards_for_JSDoc_see_with_link_tag.ts | 22 + .../generates_type_guards_for_a_Pick_type.ts | 30 + ..._type_guards_for_an_object_literal_type.ts | 27 + .../generates_type_guards_for_boolean.ts | 22 + ...,_including_when_mixed_with_static_keys.ts | 40 + ...s_for_empty_object_if_exportAll_is_true.ts | 24 + ...rds_for_interface_extending_object_type.ts | 32 + ...e_extending_object_type_with_type_guard.ts | 40 + ...for_interface_extending_other_interface.ts | 32 + ...tending_other_interface_with_type_guard.ts | 40 + ...terface_properties_with_numerical_names.ts | 29 + ...face_property_with_empty_string_as_name.ts | 27 + ...uards_for_interface_with_optional_field.ts | 34 + .../generates_type_guards_for_mapped_types.ts | 53 + ...erates_type_guards_for_nested_interface.ts | 34 + ...ds_for_nested_interface_with_type_guard.ts | 42 + ...or_property_with_non_alphanumeric_name_.ts | 75 + .../generates_type_guards_for_record_types.ts | 30 + ...nerates_type_guards_for_recursive_types.ts | 68 + ...erates_type_guards_for_simple_interface.ts | 29 + ...or_type_properties_with_numerical_names.ts | 29 + ...type_property_with_empty_string_as_name.ts | 27 + ...erates_type_guards_with_a_short_circuit.ts | 31 + ...ard_if_the_type_is_used_in_another_file.ts | 51 + ...s_key_with_underscore_if_it_goes_unused.ts | 30 + ...value_with_underscore_if_it_goes_unused.ts | 30 + .../rejects_invalid_guardFileNames.ts | 14 + ...guardts_files_when_guardFileName_is_set.ts | 11 + .../removes_existing_guardts_files.ts | 9 + tests/features/show_debug_info.ts | 72 + .../skips_checking_any_type_in_array.ts | 21 + ...nterface_has_a_different_typeguard_name.ts | 42 + ...port_file_name_if_guard_file_is_renamed.ts | 36 + tests/features/works_for_any_type.ts | 21 + tests/features/works_for_unknown_type.ts | 21 + tests/generate.ts | 1829 +---------------- 54 files changed, 1802 insertions(+), 1756 deletions(-) create mode 100644 tests/features/adds_type_guard_import_to_source_file_and_also_exports.ts create mode 100644 tests/features/allows_the_name_of_the_guard_file_file_to_be_specified.ts create mode 100644 tests/features/any_and_unknown_work_in_interesction_types.ts create mode 100644 tests/features/any_and_unknown_work_in_union_types.ts create mode 100644 tests/features/check_if_any_callable_properties_is_a_function.ts create mode 100644 tests/features/check_if_callable_interface_is_a_function.ts create mode 100644 tests/features/correctly_handles_default_export.ts create mode 100644 tests/features/deals_with_unknown_type_as_it_would_any.ts create mode 100644 tests/features/does_not_generate_empty_guard_files.ts create mode 100644 tests/features/does_not_touch_guardts_files_that_are_not_autogenerated.ts create mode 100644 tests/features/generated_type_guards_for_arrays_of_any.ts create mode 100644 tests/features/generated_type_guards_for_discriminated_unions.ts create mode 100644 tests/features/generated_type_guards_for_enums.ts create mode 100644 tests/features/generated_type_guards_for_intersection_type.ts create mode 100644 tests/features/generated_type_guards_for_nested_arrays.ts create mode 100644 tests/features/generated_type_guards_for_numeric_enums_in_optional_records.ts create mode 100644 tests/features/generated_type_guards_with_a_short_circuit_are_correctly_stripped_by_UglifyJS.ts create mode 100644 tests/features/generates_tuples.ts create mode 100644 tests/features/generates_type_guards_for_JSDoc_see_with_link_tag.ts create mode 100644 tests/features/generates_type_guards_for_a_Pick_type.ts create mode 100644 tests/features/generates_type_guards_for_an_object_literal_type.ts create mode 100644 tests/features/generates_type_guards_for_boolean.ts create mode 100644 tests/features/generates_type_guards_for_dynamic_object_keys,_including_when_mixed_with_static_keys.ts create mode 100644 tests/features/generates_type_guards_for_empty_object_if_exportAll_is_true.ts create mode 100644 tests/features/generates_type_guards_for_interface_extending_object_type.ts create mode 100644 tests/features/generates_type_guards_for_interface_extending_object_type_with_type_guard.ts create mode 100644 tests/features/generates_type_guards_for_interface_extending_other_interface.ts create mode 100644 tests/features/generates_type_guards_for_interface_extending_other_interface_with_type_guard.ts create mode 100644 tests/features/generates_type_guards_for_interface_properties_with_numerical_names.ts create mode 100644 tests/features/generates_type_guards_for_interface_property_with_empty_string_as_name.ts create mode 100644 tests/features/generates_type_guards_for_interface_with_optional_field.ts create mode 100644 tests/features/generates_type_guards_for_mapped_types.ts create mode 100644 tests/features/generates_type_guards_for_nested_interface.ts create mode 100644 tests/features/generates_type_guards_for_nested_interface_with_type_guard.ts create mode 100644 tests/features/generates_type_guards_for_property_with_non_alphanumeric_name_.ts create mode 100644 tests/features/generates_type_guards_for_record_types.ts create mode 100644 tests/features/generates_type_guards_for_recursive_types.ts create mode 100644 tests/features/generates_type_guards_for_simple_interface.ts create mode 100644 tests/features/generates_type_guards_for_type_properties_with_numerical_names.ts create mode 100644 tests/features/generates_type_guards_for_type_property_with_empty_string_as_name.ts create mode 100644 tests/features/generates_type_guards_with_a_short_circuit.ts create mode 100644 tests/features/imports_and_uses_generated_type_guard_if_the_type_is_used_in_another_file.ts create mode 100644 tests/features/prefixes_key_with_underscore_if_it_goes_unused.ts create mode 100644 tests/features/prefixes_value_with_underscore_if_it_goes_unused.ts create mode 100644 tests/features/rejects_invalid_guardFileNames.ts create mode 100644 tests/features/removes_correct_guardts_files_when_guardFileName_is_set.ts create mode 100644 tests/features/removes_existing_guardts_files.ts create mode 100644 tests/features/show_debug_info.ts create mode 100644 tests/features/skips_checking_any_type_in_array.ts create mode 100644 tests/features/type_that_is_an_alias_to_an_interface_has_a_different_typeguard_name.ts create mode 100644 tests/features/uses_correct_import_file_name_if_guard_file_is_renamed.ts create mode 100644 tests/features/works_for_any_type.ts create mode 100644 tests/features/works_for_unknown_type.ts diff --git a/tests/features/adds_type_guard_import_to_source_file_and_also_exports.ts b/tests/features/adds_type_guard_import_to_source_file_and_also_exports.ts new file mode 100644 index 0000000..8ab0229 --- /dev/null +++ b/tests/features/adds_type_guard_import_to_source_file_and_also_exports.ts @@ -0,0 +1,34 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'adds type guard import to source file and also exports', + { + // NOTE: This file is not automatically cleaned up with `formatText` after + // being modified so it requires this funky indentation to ensure that it is + // conforms to ts-morph's formatting. + 'test.ts': ` +/** @see {isEmpty} ts-auto-guard:type-guard */ +export interface Empty { } +`, + }, + { + 'test.ts': ` + import * as CustomGuardAlias from "./test.guard"; + + /** @see {isEmpty} ts-auto-guard:type-guard */ + export interface Empty {} + export { CustomGuardAlias };`, + 'test.guard.ts': ` + import { Empty } from "./test"; + + export function isEmpty(obj: unknown): obj is Empty { + const typedObj = obj as Empty + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") + ) + }`, + }, + { options: { importGuards: 'CustomGuardAlias' } } +) \ No newline at end of file diff --git a/tests/features/allows_the_name_of_the_guard_file_file_to_be_specified.ts b/tests/features/allows_the_name_of_the_guard_file_file_to_be_specified.ts new file mode 100644 index 0000000..989393f --- /dev/null +++ b/tests/features/allows_the_name_of_the_guard_file_file_to_be_specified.ts @@ -0,0 +1,34 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'allows the name of the guard file file to be specified', + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo { + foo: number, + bar: string + }`, + }, + { + 'test.ts': null, + 'test.debug.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["foo"] === "number" && + typeof typedObj["bar"] === "string" + ) + }`, + }, + { + options: { + guardFileName: 'debug', + }, + } +) \ No newline at end of file diff --git a/tests/features/any_and_unknown_work_in_interesction_types.ts b/tests/features/any_and_unknown_work_in_interesction_types.ts new file mode 100644 index 0000000..07ee4c6 --- /dev/null +++ b/tests/features/any_and_unknown_work_in_interesction_types.ts @@ -0,0 +1,41 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'any and unknown work in interesction types', + { + 'test.ts': ` + type anyType = any + type unknownType = unknown + + export type AnyAndString = string & anyType + export type UnknownAndString = string & unknownType + export type AnyAndUnknownAndString = string & anyType & unknownType`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { AnyAndString, UnknownAndString, AnyAndUnknownAndString } from "./test"; + + export function isAnyAndString(obj: unknown): obj is AnyAndString { + const typedObj = obj as AnyAndString + return ( + true + ) + } + + export function isUnknownAndString(obj: unknown): obj is UnknownAndString { + const typedObj = obj as UnknownAndString + return ( + typeof typedObj === "string" + ) + } + + export function isAnyAndUnknownAndString(obj: unknown): obj is AnyAndUnknownAndString { + const typedObj = obj as AnyAndUnknownAndString + return ( + true + ) + }`, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/features/any_and_unknown_work_in_union_types.ts b/tests/features/any_and_unknown_work_in_union_types.ts new file mode 100644 index 0000000..e7295f8 --- /dev/null +++ b/tests/features/any_and_unknown_work_in_union_types.ts @@ -0,0 +1,41 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'any and unknown work in union types', + { + 'test.ts': ` + type anyType = any + type unknownType = unknown + + export type AnyOrString = string | anyType + export type UnknownOrString = string | unknownType + export type AnyOrUnknownOrString = string | anyType | unknownType`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { AnyOrString, UnknownOrString, AnyOrUnknownOrString } from "./test"; + + export function isAnyOrString(obj: unknown): obj is AnyOrString { + const typedObj = obj as AnyOrString + return ( + true + ) + } + + export function isUnknownOrString(obj: unknown): obj is UnknownOrString { + const typedObj = obj as UnknownOrString + return ( + true + ) + } + + export function isAnyOrUnknownOrString(obj: unknown): obj is AnyOrUnknownOrString { + const typedObj = obj as AnyOrUnknownOrString + return ( + true + ) + }`, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/features/check_if_any_callable_properties_is_a_function.ts b/tests/features/check_if_any_callable_properties_is_a_function.ts new file mode 100644 index 0000000..594d7ee --- /dev/null +++ b/tests/features/check_if_any_callable_properties_is_a_function.ts @@ -0,0 +1,40 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'Check if any callable properties is a function', + // should also emit a warning about how it is not possible to check function type at runtime. + { + 'test.ts': ` + /** @see {isTestType} ts-auto-guard:type-guard */ + export interface TestType { + test: (() => void) + // ts-auto-guard-suppress function-type + test2(someArg: number): boolean + // some other comments + test3: { + (someArg: string): number + test3Arg: number; + } + } + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { TestType } from "./test"; + + export function isTestType(obj: unknown): obj is TestType { + const typedObj = obj as TestType + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["test"] === "function" && + typeof typedObj["test3"] === "function" && + typeof typedObj["test3"]["test3Arg"] === "number" && + typeof typedObj["test2"] === "function" + ) + } + `, + } +) \ No newline at end of file diff --git a/tests/features/check_if_callable_interface_is_a_function.ts b/tests/features/check_if_callable_interface_is_a_function.ts new file mode 100644 index 0000000..6fc6374 --- /dev/null +++ b/tests/features/check_if_callable_interface_is_a_function.ts @@ -0,0 +1,29 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'Check if callable interface is a function', + // should also emit a warning about how it is not possible to check function type at runtime. + { + 'test.ts': ` + /** @see {isTestType} ts-auto-guard:type-guard */ + export interface TestType { + (someArg: string): number + arg: number; + } + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { TestType } from "./test"; + + export function isTestType(obj: unknown): obj is TestType { + const typedObj = obj as TestType + return ( + typeof typedObj === "function" && + typeof typedObj["arg"] === "number" + ) + } + `, + } +) \ No newline at end of file diff --git a/tests/features/correctly_handles_default_export.ts b/tests/features/correctly_handles_default_export.ts new file mode 100644 index 0000000..29f16b8 --- /dev/null +++ b/tests/features/correctly_handles_default_export.ts @@ -0,0 +1,31 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'correctly handles default export', + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + interface Foo { + foo: number, + bar: string + } + + export default Foo`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import Foo from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["foo"] === "number" && + typeof typedObj["bar"] === "string" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/deals_with_unknown_type_as_it_would_any.ts b/tests/features/deals_with_unknown_type_as_it_would_any.ts new file mode 100644 index 0000000..32c500d --- /dev/null +++ b/tests/features/deals_with_unknown_type_as_it_would_any.ts @@ -0,0 +1,30 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'Deals with unknown type as it would any', + { + 'test.ts': ` + /** @see {isTestType} ts-auto-guard:type-guard */ + export interface TestType { + [index: string]: unknown + } + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { TestType } from "./test"; + + export function isTestType(obj: unknown): obj is TestType { + const typedObj = obj as TestType + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + Object.entries(typedObj) + .every(([key, _value]) => (typeof key === "string")) + ) + } + `, + } +) \ No newline at end of file diff --git a/tests/features/does_not_generate_empty_guard_files.ts b/tests/features/does_not_generate_empty_guard_files.ts new file mode 100644 index 0000000..f3f0932 --- /dev/null +++ b/tests/features/does_not_generate_empty_guard_files.ts @@ -0,0 +1,9 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'Does not generate empty guard files', + { + 'test.ts': '', + }, + { 'test.ts': null } +) \ No newline at end of file diff --git a/tests/features/does_not_touch_guardts_files_that_are_not_autogenerated.ts b/tests/features/does_not_touch_guardts_files_that_are_not_autogenerated.ts new file mode 100644 index 0000000..7b2d320 --- /dev/null +++ b/tests/features/does_not_touch_guardts_files_that_are_not_autogenerated.ts @@ -0,0 +1,7 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'does not touch .guard.ts files that are not autogenerated', + { 'test.guard.ts': `alert("hello")` }, + { 'test.guard.ts': null } +) \ No newline at end of file diff --git a/tests/features/generated_type_guards_for_arrays_of_any.ts b/tests/features/generated_type_guards_for_arrays_of_any.ts new file mode 100644 index 0000000..e55ffa8 --- /dev/null +++ b/tests/features/generated_type_guards_for_arrays_of_any.ts @@ -0,0 +1,28 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generated type guards for arrays of any', + { + 'test.ts': ` + export interface Foo { + value: any[] + } + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + Array.isArray(typedObj["value"]) + ) + }`, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/features/generated_type_guards_for_discriminated_unions.ts b/tests/features/generated_type_guards_for_discriminated_unions.ts new file mode 100644 index 0000000..37a0c89 --- /dev/null +++ b/tests/features/generated_type_guards_for_discriminated_unions.ts @@ -0,0 +1,32 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generated type guards for discriminated unions', + { + 'test.ts': ` + export type X = { type: 'a', value: number } | { type: 'b', value: string } + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { X } from "./test"; + + export function isX(obj: unknown): obj is X { + const typedObj = obj as X + return ( + ((typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typedObj["type"] === "a" && + typeof typedObj["value"] === "number" || + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typedObj["type"] === "b" && + typeof typedObj["value"] === "string") + ) + }`, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/features/generated_type_guards_for_enums.ts b/tests/features/generated_type_guards_for_enums.ts new file mode 100644 index 0000000..34c793d --- /dev/null +++ b/tests/features/generated_type_guards_for_enums.ts @@ -0,0 +1,28 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generated type guards for enums', + { + 'test.ts': ` + export enum Types{ + TheGood, + TheBad, + TheTypeSafe + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Types } from "./test"; + + export function isTypes(obj: unknown): obj is Types { + const typedObj = obj as Types + return ( + (typedObj === Types.TheGood || + typedObj === Types.TheBad || + typedObj === Types.TheTypeSafe) + ) + }`, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/features/generated_type_guards_for_intersection_type.ts b/tests/features/generated_type_guards_for_intersection_type.ts new file mode 100644 index 0000000..ee868b7 --- /dev/null +++ b/tests/features/generated_type_guards_for_intersection_type.ts @@ -0,0 +1,30 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generated type guards for intersection type', + { + 'test.ts': ` + export type X = { foo: number } & { bar: string } + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { X } from "./test"; + + export function isX(obj: unknown): obj is X { + const typedObj = obj as X + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["foo"] === "number" && + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["bar"] === "string" + ) + }`, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/features/generated_type_guards_for_nested_arrays.ts b/tests/features/generated_type_guards_for_nested_arrays.ts new file mode 100644 index 0000000..71fd728 --- /dev/null +++ b/tests/features/generated_type_guards_for_nested_arrays.ts @@ -0,0 +1,39 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generated type guards for nested arrays', + { + 'test.ts': ` + export type Foo = { + value: Array<{ + value: Array + }> + } + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + Array.isArray(typedObj["value"]) && + typedObj["value"].every((e: any) => + (e !== null && + typeof e === "object" || + typeof e === "function") && + Array.isArray(e["value"]) && + e["value"].every((e: any) => + typeof e === "number" + ) + ) + ) + }`, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/features/generated_type_guards_for_numeric_enums_in_optional_records.ts b/tests/features/generated_type_guards_for_numeric_enums_in_optional_records.ts new file mode 100644 index 0000000..0514021 --- /dev/null +++ b/tests/features/generated_type_guards_for_numeric_enums_in_optional_records.ts @@ -0,0 +1,49 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generated type guards for numeric enums in optional records', + { + 'test.ts': ` + export enum Types{ + TheGood = 1, + TheBad, + TheTypeSafe + } + export interface TestItem { + room: Partial>>; + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Types, TestItem } from "./test"; + + export function isTypes(obj: unknown): obj is Types { + const typedObj = obj as Types + return ( + (typedObj === Types.TheGood || + typedObj === Types.TheBad || + typedObj === Types.TheTypeSafe) + ) + } + + export function isTestItem(obj: unknown): obj is TestItem { + const typedObj = obj as TestItem + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + (typedObj["room"] !== null && + typeof typedObj["room"] === "object" || + typeof typedObj["room"] === "function") && + (typeof typedObj["room"]["1"] === "undefined" || + typeof typedObj["room"]["1"] === "string") && + (typeof typedObj["room"]["2"] === "undefined" || + typeof typedObj["room"]["2"] === "string") && + (typeof typedObj["room"]["3"] === "undefined" || + typeof typedObj["room"]["3"] === "string") + ) + }`, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/features/generated_type_guards_with_a_short_circuit_are_correctly_stripped_by_UglifyJS.ts b/tests/features/generated_type_guards_with_a_short_circuit_are_correctly_stripped_by_UglifyJS.ts new file mode 100644 index 0000000..9e62b1f --- /dev/null +++ b/tests/features/generated_type_guards_with_a_short_circuit_are_correctly_stripped_by_UglifyJS.ts @@ -0,0 +1,24 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generated type guards with a short circuit are correctly stripped by UglifyJS', + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export type Foo = { + foo: number, + bar: Foo | string | () => void, + baz: "foo" | "bar" + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': `"use strict";function isFoo(o){return!0}exports.__esModule=!0,exports.isFoo=void 0,exports.isFoo=isFoo;`, + }, + { + minifyOptions: { + compress: { global_defs: { DEBUG: true } }, + }, + options: { shortCircuitCondition: 'DEBUG', debug: false }, + } +) \ No newline at end of file diff --git a/tests/features/generates_tuples.ts b/tests/features/generates_tuples.ts new file mode 100644 index 0000000..1678145 --- /dev/null +++ b/tests/features/generates_tuples.ts @@ -0,0 +1,28 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates tuples', + { + 'test.ts': ` + export interface A { + b: [number] + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { A } from "./test"; + + export function isA(obj: unknown): obj is A { + const typedObj = obj as A + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + Array.isArray(typedObj["b"]) && + typeof typedObj["b"][0] === "number" + ) + }`, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_JSDoc_see_with_link_tag.ts b/tests/features/generates_type_guards_for_JSDoc_see_with_link_tag.ts new file mode 100644 index 0000000..f6ffff3 --- /dev/null +++ b/tests/features/generates_type_guards_for_JSDoc_see_with_link_tag.ts @@ -0,0 +1,22 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for JSDoc @see with @link tag', + { + 'test.ts': ` + /** @see {@link isBool} ts-auto-guard:type-guard */ + export type Bool = boolean`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Bool } from "./test"; + + export function isBool(obj: unknown): obj is Bool { + const typedObj = obj as Bool + return ( + typeof typedObj === "boolean" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_a_Pick_type.ts b/tests/features/generates_type_guards_for_a_Pick_type.ts new file mode 100644 index 0000000..e5b2873 --- /dev/null +++ b/tests/features/generates_type_guards_for_a_Pick_type.ts @@ -0,0 +1,30 @@ +import { testProcessProject } from '../generate' + +testProcessProject( + 'generates type guards for a Pick<> type', + { + 'test.ts': ` + interface Bar { + foo: number, + bar: number + } + + /** @see {isFoo} ts-auto-guard:type-guard */ + export type Foo = Pick`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["foo"] === "number" + ) + }`, + } +) diff --git a/tests/features/generates_type_guards_for_an_object_literal_type.ts b/tests/features/generates_type_guards_for_an_object_literal_type.ts new file mode 100644 index 0000000..7792f17 --- /dev/null +++ b/tests/features/generates_type_guards_for_an_object_literal_type.ts @@ -0,0 +1,27 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for an object literal type', + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export type Foo = { + foo: number + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["foo"] === "number" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_boolean.ts b/tests/features/generates_type_guards_for_boolean.ts new file mode 100644 index 0000000..6fbc6cc --- /dev/null +++ b/tests/features/generates_type_guards_for_boolean.ts @@ -0,0 +1,22 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for boolean', + { + 'test.ts': ` + /** @see {isBool} ts-auto-guard:type-guard */ + export type Bool = boolean`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Bool } from "./test"; + + export function isBool(obj: unknown): obj is Bool { + const typedObj = obj as Bool + return ( + typeof typedObj === "boolean" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_dynamic_object_keys,_including_when_mixed_with_static_keys.ts b/tests/features/generates_type_guards_for_dynamic_object_keys,_including_when_mixed_with_static_keys.ts new file mode 100644 index 0000000..0c33f65 --- /dev/null +++ b/tests/features/generates_type_guards_for_dynamic_object_keys,_including_when_mixed_with_static_keys.ts @@ -0,0 +1,40 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for dynamic object keys, including when mixed with static keys', + { + 'test.ts': ` + /** @see {isTestType} ts-auto-guard:type-guard */ + export interface TestType { + someKey: "some" | "key" + [index: string]: "dynamic" | "string" + [index: number]: "also-dynamic" | "number" + } + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { TestType } from "./test"; + + export function isTestType(obj: unknown): obj is TestType { + const typedObj = obj as TestType + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + (typedObj["someKey"] === "some" || + typedObj["someKey"] === "key") && + Object.entries(typedObj) + .filter(([key]) => !["someKey"].includes(key)) + .every(([key, value]) => ((value === "string" || + value === "dynamic") && + typeof key === "string" || + (value === "number" || + value === "also-dynamic") && + typeof key === "number")) + ) + } + `, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_empty_object_if_exportAll_is_true.ts b/tests/features/generates_type_guards_for_empty_object_if_exportAll_is_true.ts new file mode 100644 index 0000000..2a3be23 --- /dev/null +++ b/tests/features/generates_type_guards_for_empty_object_if_exportAll_is_true.ts @@ -0,0 +1,24 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for empty object if exportAll is true', + { + 'test.ts': ` + export interface Empty {}`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Empty } from "./test"; + + export function isEmpty(obj: unknown): obj is Empty { + const typedObj = obj as Empty + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") + ) + }`, + }, + { options: { exportAll: true, debug: false } } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_interface_extending_object_type.ts b/tests/features/generates_type_guards_for_interface_extending_object_type.ts new file mode 100644 index 0000000..88df1d6 --- /dev/null +++ b/tests/features/generates_type_guards_for_interface_extending_object_type.ts @@ -0,0 +1,32 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for interface extending object type', + { + 'test.ts': ` + export type Bar = { + bar: number + } + + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo extends Bar { + foo: number + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["bar"] === "number" && + typeof typedObj["foo"] === "number" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_interface_extending_object_type_with_type_guard.ts b/tests/features/generates_type_guards_for_interface_extending_object_type_with_type_guard.ts new file mode 100644 index 0000000..9439e54 --- /dev/null +++ b/tests/features/generates_type_guards_for_interface_extending_object_type_with_type_guard.ts @@ -0,0 +1,40 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for interface extending object type with type guard', + { + 'test.ts': ` + /** @see {isBar} ts-auto-guard:type-guard */ + export type Bar = { + bar: number + } + + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo extends Bar { + foo: number + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Bar, Foo } from "./test"; + + export function isBar(obj: unknown): obj is Bar { + const typedObj = obj as Bar + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["bar"] === "number" + ) + } + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + isBar(typedObj) as boolean && + typeof typedObj["foo"] === "number" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_interface_extending_other_interface.ts b/tests/features/generates_type_guards_for_interface_extending_other_interface.ts new file mode 100644 index 0000000..c838e09 --- /dev/null +++ b/tests/features/generates_type_guards_for_interface_extending_other_interface.ts @@ -0,0 +1,32 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for interface extending other interface', + { + 'test.ts': ` + interface Bar { + bar: number + } + + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo extends Bar { + foo: number, + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["bar"] === "number" && + typeof typedObj["foo"] === "number" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_interface_extending_other_interface_with_type_guard.ts b/tests/features/generates_type_guards_for_interface_extending_other_interface_with_type_guard.ts new file mode 100644 index 0000000..601b752 --- /dev/null +++ b/tests/features/generates_type_guards_for_interface_extending_other_interface_with_type_guard.ts @@ -0,0 +1,40 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for interface extending other interface with type guard', + { + 'test.ts': ` + /** @see {isBar} ts-auto-guard:type-guard */ + export interface Bar { + bar: number + } + + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo extends Bar { + foo: number + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Bar, Foo } from "./test"; + + export function isBar(obj: unknown): obj is Bar { + const typedObj = obj as Bar + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["bar"] === "number" + ) + } + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + isBar(typedObj) as boolean && + typeof typedObj["foo"] === "number" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_interface_properties_with_numerical_names.ts b/tests/features/generates_type_guards_for_interface_properties_with_numerical_names.ts new file mode 100644 index 0000000..c00ddf8 --- /dev/null +++ b/tests/features/generates_type_guards_for_interface_properties_with_numerical_names.ts @@ -0,0 +1,29 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for interface properties with numerical names', + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo { + "1": number, + "2": string + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["1"] === "number" && + typeof typedObj["2"] === "string" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_interface_property_with_empty_string_as_name.ts b/tests/features/generates_type_guards_for_interface_property_with_empty_string_as_name.ts new file mode 100644 index 0000000..1fcf797 --- /dev/null +++ b/tests/features/generates_type_guards_for_interface_property_with_empty_string_as_name.ts @@ -0,0 +1,27 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for interface property with empty string as name', + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo { + "": number + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj[""] === "number" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_interface_with_optional_field.ts b/tests/features/generates_type_guards_for_interface_with_optional_field.ts new file mode 100644 index 0000000..b2d98bb --- /dev/null +++ b/tests/features/generates_type_guards_for_interface_with_optional_field.ts @@ -0,0 +1,34 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for interface with optional field', + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo { + foo?: number, + bar: number | undefined, + baz?: number | undefined + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + ( typeof typedObj["foo"] === "undefined" || + typeof typedObj["foo"] === "number" ) && + ( typeof typedObj["bar"] === "undefined" || + typeof typedObj["bar"] === "number" ) && + ( typeof typedObj["baz"] === "undefined" || + typeof typedObj["baz"] === "number" ) + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_mapped_types.ts b/tests/features/generates_type_guards_for_mapped_types.ts new file mode 100644 index 0000000..30ce555 --- /dev/null +++ b/tests/features/generates_type_guards_for_mapped_types.ts @@ -0,0 +1,53 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for mapped types', + { + 'test.ts': ` + /** @see {isPropertyValueType} ts-auto-guard:type-guard */ + export type PropertyValueType = {value: string}; + + /** @see {isPropertyName} ts-auto-guard:type-guard */ + export type PropertyName = 'name' | 'value'; + + /** @see {isFoo} ts-auto-guard:type-guard */ + export type Foo = { + [key in PropertyName]: PropertyValueType + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { PropertyValueType, PropertyName, Foo } from "./test"; + + export function isPropertyValueType(obj: unknown): obj is PropertyValueType { + const typedObj = obj as PropertyValueType + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["value"] === "string" + ) + } + + export function isPropertyName(obj: unknown): obj is PropertyName { + const typedObj = obj as PropertyName + return ( + (typedObj === "name" || + typedObj === "value") + ) + } + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + isPropertyValueType(typedObj["name"]) as boolean && + isPropertyValueType(typedObj["value"]) as boolean + ) + } + `, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_nested_interface.ts b/tests/features/generates_type_guards_for_nested_interface.ts new file mode 100644 index 0000000..01bced3 --- /dev/null +++ b/tests/features/generates_type_guards_for_nested_interface.ts @@ -0,0 +1,34 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for nested interface', + { + 'test.ts': ` + interface Bar { + bar: number + } + + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo { + foo: Bar, + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + (typedObj["foo"] !== null && + typeof typedObj["foo"] === "object" || + typeof typedObj["foo"] === "function") && + typeof typedObj["foo"]["bar"] === "number" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_nested_interface_with_type_guard.ts b/tests/features/generates_type_guards_for_nested_interface_with_type_guard.ts new file mode 100644 index 0000000..439c883 --- /dev/null +++ b/tests/features/generates_type_guards_for_nested_interface_with_type_guard.ts @@ -0,0 +1,42 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for nested interface with type guard', + { + 'test.ts': ` + /** @see {isBar} ts-auto-guard:type-guard */ + export interface Bar { + bar: number + } + + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo { + foo: Bar, + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Bar, Foo } from "./test"; + + export function isBar(obj: unknown): obj is Bar { + const typedObj = obj as Bar + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["bar"] === "number" + ) + } + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + isBar(typedObj["foo"]) as boolean + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_property_with_non_alphanumeric_name_.ts b/tests/features/generates_type_guards_for_property_with_non_alphanumeric_name_.ts new file mode 100644 index 0000000..f26094c --- /dev/null +++ b/tests/features/generates_type_guards_for_property_with_non_alphanumeric_name_.ts @@ -0,0 +1,75 @@ +// characters that are currently not supported include double quotes, backslashes and newlines +import { testProcessProject } from '../generate' + +const nonAlphanumericCharacterPropertyNames = [ + '\0', + ' ', + '-', + '+', + '*', + '/', + '.', + 'foo bar', + 'foo-bar', + 'foo+bar', + 'foo*bar', + 'foo/bar', + 'foo.bar', + "'foobar'", + '#hashtag', + '1337_leadingNumbers', +] + +for (const propertyName of nonAlphanumericCharacterPropertyNames) { + testProcessProject( + `generates type guards for interface property with non-alphanumeric name '${propertyName}'`, + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo { + "${propertyName}": number + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["${propertyName}"] === "number" + ) + }`, + } + ) + + testProcessProject( + `generates type guards for type property with non-alphanumeric name '${propertyName}'`, + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export type Foo = { + "${propertyName}": number + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["${propertyName}"] === "number" + ) + }`, + } + ) +} diff --git a/tests/features/generates_type_guards_for_record_types.ts b/tests/features/generates_type_guards_for_record_types.ts new file mode 100644 index 0000000..51c4c5c --- /dev/null +++ b/tests/features/generates_type_guards_for_record_types.ts @@ -0,0 +1,30 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for Record types', + { + 'test.ts': ` + /** @see {isTestType} ts-auto-guard:type-guard */ + export type TestType = Record + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { TestType } from "./test"; + + export function isTestType(obj: unknown): obj is TestType { + const typedObj = obj as TestType + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + Object.entries(typedObj) + .every(([key, value]) => ((value === "string" || + value === "dynamic") && + typeof key === "string")) + ) + } + `, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_recursive_types.ts b/tests/features/generates_type_guards_for_recursive_types.ts new file mode 100644 index 0000000..99fc8be --- /dev/null +++ b/tests/features/generates_type_guards_for_recursive_types.ts @@ -0,0 +1,68 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for recursive types', + { + 'test.ts': ` + /** @see {isBranch1} ts-auto-guard:type-guard */ + export type Branch1 = Branch1[] | string; + + /** @see {isBranch2} ts-auto-guard:type-guard */ + export type Branch2 = { branches: Branch2[] } | string; + + /** @see {isBranch3} ts-auto-guard:type-guard */ + export type Branch3 = { branches: Branch3[] } | {branches: Branch3 }[] | string; + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Branch1, Branch2, Branch3 } from "./test"; + + export function isBranch1(obj: unknown): obj is Branch1 { + const typedObj = obj as Branch1 + return ( + (typeof typedObj === "string" || + Array.isArray(typedObj) && + typedObj.every((e: any) => + isBranch1(e) as boolean + )) + ) + } + + export function isBranch2(obj: unknown): obj is Branch2 { + const typedObj = obj as Branch2 + return ( + (typeof typedObj === "string" || + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + Array.isArray(typedObj["branches"]) && + typedObj["branches"].every((e: any) => + isBranch2(e) as boolean + )) + ) + } + + export function isBranch3(obj: unknown): obj is Branch3 { + const typedObj = obj as Branch3 + return ( + (typeof typedObj === "string" || + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + Array.isArray(typedObj["branches"]) && + typedObj["branches"].every((e: any) => + isBranch3(e) as boolean + ) || + Array.isArray(typedObj) && + typedObj.every((e: any) => + (e !== null && + typeof e === "object" || + typeof e === "function") && + isBranch3(e["branches"]) as boolean + )) + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_simple_interface.ts b/tests/features/generates_type_guards_for_simple_interface.ts new file mode 100644 index 0000000..8ad762b --- /dev/null +++ b/tests/features/generates_type_guards_for_simple_interface.ts @@ -0,0 +1,29 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for simple interface', + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo { + foo: number, + bar: string + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["foo"] === "number" && + typeof typedObj["bar"] === "string" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_type_properties_with_numerical_names.ts b/tests/features/generates_type_guards_for_type_properties_with_numerical_names.ts new file mode 100644 index 0000000..71361fe --- /dev/null +++ b/tests/features/generates_type_guards_for_type_properties_with_numerical_names.ts @@ -0,0 +1,29 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for type properties with numerical names', + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export type Foo = { + "1": number, + "2": string + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["1"] === "number" && + typeof typedObj["2"] === "string" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_for_type_property_with_empty_string_as_name.ts b/tests/features/generates_type_guards_for_type_property_with_empty_string_as_name.ts new file mode 100644 index 0000000..7daf672 --- /dev/null +++ b/tests/features/generates_type_guards_for_type_property_with_empty_string_as_name.ts @@ -0,0 +1,27 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards for type property with empty string as name', + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export type Foo = { + "": number + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj[""] === "number" + ) + }`, + } +) \ No newline at end of file diff --git a/tests/features/generates_type_guards_with_a_short_circuit.ts b/tests/features/generates_type_guards_with_a_short_circuit.ts new file mode 100644 index 0000000..9d0482d --- /dev/null +++ b/tests/features/generates_type_guards_with_a_short_circuit.ts @@ -0,0 +1,31 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'generates type guards with a short circuit', + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export type Foo = { + foo: number + }`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + if (DEBUG) return true + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["foo"] === "number" + ) + }`, + }, + { + options: { shortCircuitCondition: 'DEBUG', debug: false }, + } +) \ No newline at end of file diff --git a/tests/features/imports_and_uses_generated_type_guard_if_the_type_is_used_in_another_file.ts b/tests/features/imports_and_uses_generated_type_guard_if_the_type_is_used_in_another_file.ts new file mode 100644 index 0000000..5c3169e --- /dev/null +++ b/tests/features/imports_and_uses_generated_type_guard_if_the_type_is_used_in_another_file.ts @@ -0,0 +1,51 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'imports and uses generated type guard if the type is used in another file', + { + 'test.ts': ` + /** @see {isTestType} ts-auto-guard:type-guard */ + export interface TestType { + someKey: string | number + } + `, + 'test-list.ts': ` + import { TestType } from './test' + + /** @see {isTestTypeList} ts-auto-guard:type-guard */ + export type TestTypeList = Array + `, + }, + { + 'test.ts': null, + 'test-list.ts': null, + 'test-list.guard.ts': ` + import { isTestType } from "./test.guard"; + import { TestTypeList } from "./test-list"; + + export function isTestTypeList(obj: unknown): obj is TestTypeList { + const typedObj = obj as TestTypeList + return ( + Array.isArray(typedObj) && + typedObj.every((e: any) => + isTestType(e) as boolean + ) + ) + } + `, + 'test.guard.ts': ` + import { TestType } from "./test"; + + export function isTestType(obj: unknown): obj is TestType { + const typedObj = obj as TestType + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + (typeof typedObj["someKey"] === "string" || + typeof typedObj["someKey"] === "number") + ) + } + `, + } +) \ No newline at end of file diff --git a/tests/features/prefixes_key_with_underscore_if_it_goes_unused.ts b/tests/features/prefixes_key_with_underscore_if_it_goes_unused.ts new file mode 100644 index 0000000..a701b70 --- /dev/null +++ b/tests/features/prefixes_key_with_underscore_if_it_goes_unused.ts @@ -0,0 +1,30 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'prefixes key with underscore if it goes unused', + { + 'test.ts': ` + /** @see {isTestType} ts-auto-guard:type-guard */ + export interface TestType { + [index: any]: string + } + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { TestType } from "./test"; + + export function isTestType(obj: unknown): obj is TestType { + const typedObj = obj as TestType + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + Object.entries(typedObj) + .every(([_key, value]) => (typeof value === "string")) + ) + } + `, + } +) \ No newline at end of file diff --git a/tests/features/prefixes_value_with_underscore_if_it_goes_unused.ts b/tests/features/prefixes_value_with_underscore_if_it_goes_unused.ts new file mode 100644 index 0000000..8ceaea4 --- /dev/null +++ b/tests/features/prefixes_value_with_underscore_if_it_goes_unused.ts @@ -0,0 +1,30 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'prefixes value with underscore if it goes unused', + { + 'test.ts': ` + /** @see {isTestType} ts-auto-guard:type-guard */ + export interface TestType { + [index: string]: any + } + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { TestType } from "./test"; + + export function isTestType(obj: unknown): obj is TestType { + const typedObj = obj as TestType + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + Object.entries(typedObj) + .every(([key, _value]) => (typeof key === "string")) + ) + } + `, + } +) \ No newline at end of file diff --git a/tests/features/rejects_invalid_guardFileNames.ts b/tests/features/rejects_invalid_guardFileNames.ts new file mode 100644 index 0000000..e02b6af --- /dev/null +++ b/tests/features/rejects_invalid_guardFileNames.ts @@ -0,0 +1,14 @@ +import { testProcessProject } from '../generate' + +const invalidGuardFileNameCharacters = ['*', '/'] +for (const invalidCharacter of invalidGuardFileNameCharacters) { + testProcessProject( + `rejects invalid guardFileNames: ${invalidCharacter}`, + {}, + {}, + { + options: { guardFileName: `f${invalidCharacter}o` }, + throws: /guardFileName/, + } + ) +} diff --git a/tests/features/removes_correct_guardts_files_when_guardFileName_is_set.ts b/tests/features/removes_correct_guardts_files_when_guardFileName_is_set.ts new file mode 100644 index 0000000..48fc62b --- /dev/null +++ b/tests/features/removes_correct_guardts_files_when_guardFileName_is_set.ts @@ -0,0 +1,11 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'removes correct .guard.ts files when guardFileName is set', + { + 'test.foo.ts': `/* WARNING: Do not manually change this file. */alert("hello")`, + 'test.guard.ts': `/* WARNING: Do not manually change this file. */alert("hello")`, + }, + { 'test.guard.ts': null }, + { options: { guardFileName: 'foo' } } +) \ No newline at end of file diff --git a/tests/features/removes_existing_guardts_files.ts b/tests/features/removes_existing_guardts_files.ts new file mode 100644 index 0000000..037c102 --- /dev/null +++ b/tests/features/removes_existing_guardts_files.ts @@ -0,0 +1,9 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'removes existing .guard.ts files', + { + 'test.guard.ts': `/* WARNING: Do not manually change this file. */ alert("hello")`, + }, + {} +) \ No newline at end of file diff --git a/tests/features/show_debug_info.ts b/tests/features/show_debug_info.ts new file mode 100644 index 0000000..3e09a26 --- /dev/null +++ b/tests/features/show_debug_info.ts @@ -0,0 +1,72 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'show debug info', + { + [`foo/bar/test.ts`]: ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo { + foo: number, + bar: Bar, + bars: Array + } + + /** @see {isBar} ts-auto-guard:type-guard */ + export interface Bar { + bar: number, + } + + `, + }, + { + [`foo/bar/test.ts`]: null, + [`foo/bar/test.guard.ts`]: ` + import { Foo, Bar } from "./test"; + + function evaluate( + isCorrect: boolean, + varName: string, + expected: string, + actual: any + ): boolean { + if (!isCorrect) { + console.error( + \`\${varName} type mismatch, expected: \${expected}, found:\`, + actual + ) + } + return isCorrect + } + + export function isFoo(obj: unknown, argumentName: string = "foo"): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + evaluate(typeof typedObj["foo"] === "number", \`\${argumentName}["foo"]\`, "number", typedObj["foo"]) && + evaluate(isBar(typedObj["bar"]) as boolean, \`\${argumentName}["bar"]\`, "import(\\"/foo/bar/test\\").Bar", typedObj["bar"]) && + evaluate(Array.isArray(typedObj["bars"]) && + typedObj["bars"].every((e: any) => + isBar(e) as boolean + ), \`\${argumentName}["bars"]\`, "import(\\"/foo/bar/test\\").Bar[]", typedObj["bars"]) + ) + } + + export function isBar(obj: unknown, argumentName: string = "bar"): obj is Bar { + const typedObj = obj as Bar + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + evaluate(typeof typedObj["bar"] === "number", \`\${argumentName}["bar"]\`, "number", typedObj["bar"]) + ) + } + `, + }, + { + options: { + debug: true, + }, + } +) \ No newline at end of file diff --git a/tests/features/skips_checking_any_type_in_array.ts b/tests/features/skips_checking_any_type_in_array.ts new file mode 100644 index 0000000..a449c4f --- /dev/null +++ b/tests/features/skips_checking_any_type_in_array.ts @@ -0,0 +1,21 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'skips checking any type in array', + { + 'test.ts': `export type A = any[]`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { A } from "./test"; + + export function isA(obj: unknown): obj is A { + const typedObj = obj as A + return ( + Array.isArray(typedObj) + ) + }`, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/features/type_that_is_an_alias_to_an_interface_has_a_different_typeguard_name.ts b/tests/features/type_that_is_an_alias_to_an_interface_has_a_different_typeguard_name.ts new file mode 100644 index 0000000..f68b714 --- /dev/null +++ b/tests/features/type_that_is_an_alias_to_an_interface_has_a_different_typeguard_name.ts @@ -0,0 +1,42 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'type that is an alias to an interface has a different typeguard name', + { + 'test.ts': ` + export interface TestType { + [index: any]: string + } + export type SecondaryTestType = TestType + `, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { TestType, SecondaryTestType } from "./test"; + + export function isTestType(obj: unknown): obj is TestType { + const typedObj = obj as TestType + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + Object.entries(typedObj) + .every(([_key, value]) => (typeof value === "string")) + ) + } + + export function isSecondaryTestType(obj: unknown): obj is SecondaryTestType { + const typedObj = obj as SecondaryTestType + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + Object.entries(typedObj) + .every(([_key, value]) => (typeof value === "string")) + ) + } + `, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/features/uses_correct_import_file_name_if_guard_file_is_renamed.ts b/tests/features/uses_correct_import_file_name_if_guard_file_is_renamed.ts new file mode 100644 index 0000000..a173027 --- /dev/null +++ b/tests/features/uses_correct_import_file_name_if_guard_file_is_renamed.ts @@ -0,0 +1,36 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'uses correct import file name if guard file is renamed', + { + 'test.ts': ` + /** @see {isFoo} ts-auto-guard:type-guard */ + export interface Foo { + foo: number, + bar: string + }`, + }, + { + 'test.ts': null, + 'test.debug.ts': ` + import { Foo } from "./test"; + + export function isFoo(obj: unknown): obj is Foo { + const typedObj = obj as Foo + return ( + (typedObj !== null && + typeof typedObj === "object" || + typeof typedObj === "function") && + typeof typedObj["foo"] === "number" && + typeof typedObj["bar"] === "string" + ) + }`, + }, + { + options: { + guardFileName: 'debug', + importGuards: 'CustomGuardAlias', + }, + skip: true, + } +) \ No newline at end of file diff --git a/tests/features/works_for_any_type.ts b/tests/features/works_for_any_type.ts new file mode 100644 index 0000000..dfb54cb --- /dev/null +++ b/tests/features/works_for_any_type.ts @@ -0,0 +1,21 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'works for any type', + { + 'test.ts': `export type A = any`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { A } from "./test"; + + export function isA(obj: unknown): obj is A { + const typedObj = obj as A + return ( + true + ) + }`, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/features/works_for_unknown_type.ts b/tests/features/works_for_unknown_type.ts new file mode 100644 index 0000000..c2b4a39 --- /dev/null +++ b/tests/features/works_for_unknown_type.ts @@ -0,0 +1,21 @@ +import {testProcessProject} from '../generate'; + +testProcessProject( + 'works for unknown type', + { + 'test.ts': `export type A = unknown`, + }, + { + 'test.ts': null, + 'test.guard.ts': ` + import { A } from "./test"; + + export function isA(obj: unknown): obj is A { + const typedObj = obj as A + return ( + true + ) + }`, + }, + { options: { exportAll: true } } +) \ No newline at end of file diff --git a/tests/generate.ts b/tests/generate.ts index 9d91707..fe1150d 100644 --- a/tests/generate.ts +++ b/tests/generate.ts @@ -1,16 +1,15 @@ -// import test from 'tape' -// import { Project } from 'ts-morph' -import { MinifyOptions } from 'uglify-js' -import { IProcessOptions } from '../src' -import fs from 'fs' - -// function createProject(): Project { -// return new Project({ -// skipAddingFilesFromTsConfig: true, -// compilerOptions: { strict: true }, -// useInMemoryFileSystem: true, -// }) -// } +import test from 'tape' +import { Project } from 'ts-morph' +import { minify, MinifyOptions } from 'uglify-js' +import { IProcessOptions, processProject } from '../src' + +function createProject(): Project { + return new Project({ + skipAddingFilesFromTsConfig: true, + compilerOptions: { strict: true }, + useInMemoryFileSystem: true, + }) +} interface ITestOptions { skip?: boolean @@ -20,1754 +19,72 @@ interface ITestOptions { throws?: RegExp | typeof Error } -function replaceAll(str: string, match: string, replacement: string) { - return str.split(match).join(replacement) -} - -const src = fs.readFileSync(__filename, 'utf-8') -const lines = src.split('\r\n') - export function testProcessProject( typeDescription: string, - _: { readonly [filename: string]: string }, - _0: { readonly [filename: string]: string | null }, - _1: ITestOptions = {} -) { - const name = replaceAll(replaceAll(typeDescription, ' ', '_'), '.', '') - let titleLine: number | false = false - let endLine: number | false = false - const blockLines = [] - blockLines.push("import {testProcessProject} from '../generate';") - blockLines.push('') - for (let i = 0; i < lines.length; i++) { - if (titleLine === false) { - const titleI = lines[i].indexOf(typeDescription) - if (titleI > 0) { - titleLine = i - blockLines.push(lines[i - 1]) - blockLines.push(lines[i]) - } - } else { - blockLines.push(lines[i]) - if (lines[i] === ')') { - endLine = i - break - } - } - } - if (titleLine === false || endLine === false) { - console.log('skipped : ' + name) - } else { - try { - fs.writeFileSync( - __dirname + '/features/' + name + '.ts', - blockLines.join('\r\n'), - 'utf-8' - ) - } catch (e) { - console.log('skipped (due to error) : ' + name) - } - } -} - -testProcessProject( - 'removes existing .guard.ts files', - { - 'test.guard.ts': `/* WARNING: Do not manually change this file. */ alert("hello")`, - }, - {} -) - -testProcessProject( - 'does not touch .guard.ts files that are not autogenerated', - { 'test.guard.ts': `alert("hello")` }, - { 'test.guard.ts': null } -) - -testProcessProject( - 'removes correct .guard.ts files when guardFileName is set', - { - 'test.foo.ts': `/* WARNING: Do not manually change this file. */alert("hello")`, - 'test.guard.ts': `/* WARNING: Do not manually change this file. */alert("hello")`, - }, - { 'test.guard.ts': null }, - { options: { guardFileName: 'foo' } } -) - -const invalidGuardFileNameCharacters = ['*', '/'] -for (const invalidCharacter of invalidGuardFileNameCharacters) { - testProcessProject( - `rejects invalid guardFileNames: ${invalidCharacter}`, - {}, - {}, - { - options: { guardFileName: `f${invalidCharacter}o` }, - throws: /guardFileName/, - } - ) -} - -testProcessProject( - 'generates type guards for empty object if exportAll is true', - { - 'test.ts': ` - export interface Empty {}`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Empty } from "./test"; - - export function isEmpty(obj: unknown): obj is Empty { - const typedObj = obj as Empty - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") - ) - }`, - }, - { options: { exportAll: true, debug: false } } -) - -testProcessProject( - 'generates type guards for JSDoc @see with @link tag', - { - 'test.ts': ` - /** @see {@link isBool} ts-auto-guard:type-guard */ - export type Bool = boolean`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Bool } from "./test"; - - export function isBool(obj: unknown): obj is Bool { - const typedObj = obj as Bool - return ( - typeof typedObj === "boolean" - ) - }`, - } -) - -testProcessProject( - 'generates type guards for boolean', - { - 'test.ts': ` - /** @see {isBool} ts-auto-guard:type-guard */ - export type Bool = boolean`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Bool } from "./test"; - - export function isBool(obj: unknown): obj is Bool { - const typedObj = obj as Bool - return ( - typeof typedObj === "boolean" - ) - }`, - } -) - -testProcessProject( - 'allows the name of the guard file file to be specified', - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo { - foo: number, - bar: string - }`, - }, - { - 'test.ts': null, - 'test.debug.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["foo"] === "number" && - typeof typedObj["bar"] === "string" - ) - }`, - }, - { - options: { - guardFileName: 'debug', - }, - } -) - -testProcessProject( - 'show debug info', - { - [`foo/bar/test.ts`]: ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo { - foo: number, - bar: Bar, - bars: Array - } - - /** @see {isBar} ts-auto-guard:type-guard */ - export interface Bar { - bar: number, - } - - `, - }, - { - [`foo/bar/test.ts`]: null, - [`foo/bar/test.guard.ts`]: ` - import { Foo, Bar } from "./test"; - - function evaluate( - isCorrect: boolean, - varName: string, - expected: string, - actual: any - ): boolean { - if (!isCorrect) { - console.error( - \`\${varName} type mismatch, expected: \${expected}, found:\`, - actual - ) - } - return isCorrect - } - - export function isFoo(obj: unknown, argumentName: string = "foo"): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - evaluate(typeof typedObj["foo"] === "number", \`\${argumentName}["foo"]\`, "number", typedObj["foo"]) && - evaluate(isBar(typedObj["bar"]) as boolean, \`\${argumentName}["bar"]\`, "import(\\"/foo/bar/test\\").Bar", typedObj["bar"]) && - evaluate(Array.isArray(typedObj["bars"]) && - typedObj["bars"].every((e: any) => - isBar(e) as boolean - ), \`\${argumentName}["bars"]\`, "import(\\"/foo/bar/test\\").Bar[]", typedObj["bars"]) - ) - } - - export function isBar(obj: unknown, argumentName: string = "bar"): obj is Bar { - const typedObj = obj as Bar - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - evaluate(typeof typedObj["bar"] === "number", \`\${argumentName}["bar"]\`, "number", typedObj["bar"]) - ) - } - `, - }, - { - options: { - debug: true, - }, - } -) - -testProcessProject( - 'uses correct import file name if guard file is renamed', - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo { - foo: number, - bar: string - }`, - }, - { - 'test.ts': null, - 'test.debug.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["foo"] === "number" && - typeof typedObj["bar"] === "string" - ) - }`, - }, - { - options: { - guardFileName: 'debug', - importGuards: 'CustomGuardAlias', - }, - skip: true, - } -) - -testProcessProject( - 'generates type guards for simple interface', - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo { - foo: number, - bar: string - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["foo"] === "number" && - typeof typedObj["bar"] === "string" - ) - }`, - } -) - -// characters that are currently not supported include double quotes, backslashes and newlines -const nonAlphanumericCharacterPropertyNames = [ - '\0', - ' ', - '-', - '+', - '*', - '/', - '.', - 'foo bar', - 'foo-bar', - 'foo+bar', - 'foo*bar', - 'foo/bar', - 'foo.bar', - "'foobar'", - '#hashtag', - '1337_leadingNumbers', -] - -for (const propertyName of nonAlphanumericCharacterPropertyNames) { - testProcessProject( - `generates type guards for interface property with non-alphanumeric name '${propertyName}'`, - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo { - "${propertyName}": number - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["${propertyName}"] === "number" - ) - }`, - } - ) - - testProcessProject( - `generates type guards for type property with non-alphanumeric name '${propertyName}'`, - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export type Foo = { - "${propertyName}": number - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["${propertyName}"] === "number" - ) - }`, - } - ) -} - -testProcessProject( - 'generates type guards for interface properties with numerical names', - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo { - "1": number, - "2": string - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["1"] === "number" && - typeof typedObj["2"] === "string" - ) - }`, - } -) - -testProcessProject( - 'generates type guards for type properties with numerical names', - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export type Foo = { - "1": number, - "2": string - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["1"] === "number" && - typeof typedObj["2"] === "string" - ) - }`, - } -) -testProcessProject( - 'generates type guards for interface property with empty string as name', - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo { - "": number - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj[""] === "number" - ) - }`, - } -) - -testProcessProject( - 'generates type guards for type property with empty string as name', - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export type Foo = { - "": number - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj[""] === "number" - ) - }`, - } -) - -testProcessProject( - 'correctly handles default export', - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - interface Foo { - foo: number, - bar: string - } - - export default Foo`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import Foo from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["foo"] === "number" && - typeof typedObj["bar"] === "string" - ) - }`, - } -) - -testProcessProject( - 'generates type guards for interface with optional field', - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo { - foo?: number, - bar: number | undefined, - baz?: number | undefined - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - ( typeof typedObj["foo"] === "undefined" || - typeof typedObj["foo"] === "number" ) && - ( typeof typedObj["bar"] === "undefined" || - typeof typedObj["bar"] === "number" ) && - ( typeof typedObj["baz"] === "undefined" || - typeof typedObj["baz"] === "number" ) - ) - }`, - } -) - -testProcessProject( - 'generates type guards for nested interface', - { - 'test.ts': ` - interface Bar { - bar: number - } - - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo { - foo: Bar, - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - (typedObj["foo"] !== null && - typeof typedObj["foo"] === "object" || - typeof typedObj["foo"] === "function") && - typeof typedObj["foo"]["bar"] === "number" - ) - }`, - } -) - -testProcessProject( - 'generates type guards for nested interface with type guard', - { - 'test.ts': ` - /** @see {isBar} ts-auto-guard:type-guard */ - export interface Bar { - bar: number - } - - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo { - foo: Bar, - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Bar, Foo } from "./test"; - - export function isBar(obj: unknown): obj is Bar { - const typedObj = obj as Bar - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["bar"] === "number" - ) - } - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - isBar(typedObj["foo"]) as boolean - ) - }`, - } -) - -testProcessProject( - 'generates type guards for interface extending other interface', - { - 'test.ts': ` - interface Bar { - bar: number - } - - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo extends Bar { - foo: number, - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["bar"] === "number" && - typeof typedObj["foo"] === "number" - ) - }`, - } -) - -testProcessProject( - 'generates type guards for interface extending other interface with type guard', - { - 'test.ts': ` - /** @see {isBar} ts-auto-guard:type-guard */ - export interface Bar { - bar: number - } - - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo extends Bar { - foo: number - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Bar, Foo } from "./test"; - - export function isBar(obj: unknown): obj is Bar { - const typedObj = obj as Bar - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["bar"] === "number" - ) - } - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - isBar(typedObj) as boolean && - typeof typedObj["foo"] === "number" - ) - }`, - } -) - -testProcessProject( - 'generates type guards for interface extending object type', - { - 'test.ts': ` - export type Bar = { - bar: number - } - - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo extends Bar { - foo: number - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["bar"] === "number" && - typeof typedObj["foo"] === "number" - ) - }`, - } -) - -testProcessProject( - 'generates type guards for interface extending object type with type guard', - { - 'test.ts': ` - /** @see {isBar} ts-auto-guard:type-guard */ - export type Bar = { - bar: number - } - - /** @see {isFoo} ts-auto-guard:type-guard */ - export interface Foo extends Bar { - foo: number - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Bar, Foo } from "./test"; - - export function isBar(obj: unknown): obj is Bar { - const typedObj = obj as Bar - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["bar"] === "number" - ) - } - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - isBar(typedObj) as boolean && - typeof typedObj["foo"] === "number" - ) - }`, - } -) - -testProcessProject( - 'generates type guards for an object literal type', - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export type Foo = { - foo: number - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["foo"] === "number" - ) - }`, - } -) - -testProcessProject( - 'generates type guards for a Pick<> type', - { - 'test.ts': ` - interface Bar { - foo: number, - bar: number - } - - /** @see {isFoo} ts-auto-guard:type-guard */ - export type Foo = Pick`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["foo"] === "number" - ) - }`, - } -) - -testProcessProject( - 'generates type guards with a short circuit', - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export type Foo = { - foo: number - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - if (DEBUG) return true - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["foo"] === "number" - ) - }`, - }, - { - options: { shortCircuitCondition: 'DEBUG', debug: false }, - } -) - -testProcessProject( - 'generated type guards with a short circuit are correctly stripped by UglifyJS', - { - 'test.ts': ` - /** @see {isFoo} ts-auto-guard:type-guard */ - export type Foo = { - foo: number, - bar: Foo | string | () => void, - baz: "foo" | "bar" - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': `"use strict";function isFoo(o){return!0}exports.__esModule=!0,exports.isFoo=void 0,exports.isFoo=isFoo;`, - }, - { - minifyOptions: { - compress: { global_defs: { DEBUG: true } }, - }, - options: { shortCircuitCondition: 'DEBUG', debug: false }, - } -) - -testProcessProject( - 'generates type guards for mapped types', - { - 'test.ts': ` - /** @see {isPropertyValueType} ts-auto-guard:type-guard */ - export type PropertyValueType = {value: string}; - - /** @see {isPropertyName} ts-auto-guard:type-guard */ - export type PropertyName = 'name' | 'value'; - - /** @see {isFoo} ts-auto-guard:type-guard */ - export type Foo = { - [key in PropertyName]: PropertyValueType - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { PropertyValueType, PropertyName, Foo } from "./test"; - - export function isPropertyValueType(obj: unknown): obj is PropertyValueType { - const typedObj = obj as PropertyValueType - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["value"] === "string" - ) - } - - export function isPropertyName(obj: unknown): obj is PropertyName { - const typedObj = obj as PropertyName - return ( - (typedObj === "name" || - typedObj === "value") - ) - } - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - isPropertyValueType(typedObj["name"]) as boolean && - isPropertyValueType(typedObj["value"]) as boolean - ) - } - `, - } -) - -testProcessProject( - 'generates type guards for recursive types', - { - 'test.ts': ` - /** @see {isBranch1} ts-auto-guard:type-guard */ - export type Branch1 = Branch1[] | string; - - /** @see {isBranch2} ts-auto-guard:type-guard */ - export type Branch2 = { branches: Branch2[] } | string; - - /** @see {isBranch3} ts-auto-guard:type-guard */ - export type Branch3 = { branches: Branch3[] } | {branches: Branch3 }[] | string; - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Branch1, Branch2, Branch3 } from "./test"; - - export function isBranch1(obj: unknown): obj is Branch1 { - const typedObj = obj as Branch1 - return ( - (typeof typedObj === "string" || - Array.isArray(typedObj) && - typedObj.every((e: any) => - isBranch1(e) as boolean - )) - ) - } - - export function isBranch2(obj: unknown): obj is Branch2 { - const typedObj = obj as Branch2 - return ( - (typeof typedObj === "string" || - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - Array.isArray(typedObj["branches"]) && - typedObj["branches"].every((e: any) => - isBranch2(e) as boolean - )) - ) - } - - export function isBranch3(obj: unknown): obj is Branch3 { - const typedObj = obj as Branch3 - return ( - (typeof typedObj === "string" || - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - Array.isArray(typedObj["branches"]) && - typedObj["branches"].every((e: any) => - isBranch3(e) as boolean - ) || - Array.isArray(typedObj) && - typedObj.every((e: any) => - (e !== null && - typeof e === "object" || - typeof e === "function") && - isBranch3(e["branches"]) as boolean - )) - ) - }`, - } -) - -testProcessProject( - 'generated type guards for discriminated unions', - { - 'test.ts': ` - export type X = { type: 'a', value: number } | { type: 'b', value: string } - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { X } from "./test"; - - export function isX(obj: unknown): obj is X { - const typedObj = obj as X - return ( - ((typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typedObj["type"] === "a" && - typeof typedObj["value"] === "number" || - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typedObj["type"] === "b" && - typeof typedObj["value"] === "string") - ) - }`, - }, - { options: { exportAll: true } } -) - -testProcessProject( - 'generated type guards for enums', - { - 'test.ts': ` - export enum Types{ - TheGood, - TheBad, - TheTypeSafe - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Types } from "./test"; - - export function isTypes(obj: unknown): obj is Types { - const typedObj = obj as Types - return ( - (typedObj === Types.TheGood || - typedObj === Types.TheBad || - typedObj === Types.TheTypeSafe) - ) - }`, - }, - { options: { exportAll: true } } -) - -testProcessProject( - 'generated type guards for numeric enums in optional records', - { - 'test.ts': ` - export enum Types{ - TheGood = 1, - TheBad, - TheTypeSafe - } - export interface TestItem { - room: Partial>>; - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Types, TestItem } from "./test"; - - export function isTypes(obj: unknown): obj is Types { - const typedObj = obj as Types - return ( - (typedObj === Types.TheGood || - typedObj === Types.TheBad || - typedObj === Types.TheTypeSafe) - ) - } - - export function isTestItem(obj: unknown): obj is TestItem { - const typedObj = obj as TestItem - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - (typedObj["room"] !== null && - typeof typedObj["room"] === "object" || - typeof typedObj["room"] === "function") && - (typeof typedObj["room"]["1"] === "undefined" || - typeof typedObj["room"]["1"] === "string") && - (typeof typedObj["room"]["2"] === "undefined" || - typeof typedObj["room"]["2"] === "string") && - (typeof typedObj["room"]["3"] === "undefined" || - typeof typedObj["room"]["3"] === "string") + input: { readonly [filename: string]: string }, + output: { readonly [filename: string]: string | null }, + { skip, only, options, minifyOptions, throws }: ITestOptions = {} +): void { + const fn = skip ? test.skip : only ? test.only : test + fn(typeDescription, t => { + const project = createProject() + Object.entries(input).forEach(([filePath, content]) => { + project.createSourceFile(filePath, content) + }) + project.saveSync() + + const expectedFilenames = new Set(Object.keys(output)) + + if (throws) { + t.throws(() => { + processProject(project, options) + }, throws) + t.end() + return + } + + t.doesNotThrow(() => { + processProject(project, options) + }) + + for (const sourceFile of project.getSourceFiles()) { + const filePath = sourceFile.getFilePath().slice(1) + const expectedRaw = output[filePath] + if (expectedRaw === undefined) { + t.fail(`unexpected file ${filePath}`) + } else if (expectedRaw === null) { + // This file is expected, but must not have been changed + expectedFilenames.delete(filePath) + const sourceText = sourceFile.getFullText() + t.equal(sourceText, input[filePath], `${filePath} should not change`) + } else { + // This is a new file + expectedFilenames.delete(filePath) + const expectedFile = project.createSourceFile( + `${filePath}.expected`, + expectedRaw + ) + let sourceText: string + if (minifyOptions !== undefined) { + const emitOutput = sourceFile.getEmitOutput() + const result = minify( + emitOutput.getOutputFiles()[0].getText(), + minifyOptions ) - }`, - }, - { options: { exportAll: true } } -) - -testProcessProject( - 'generated type guards for arrays of any', - { - 'test.ts': ` - export interface Foo { - value: any[] - } - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - Array.isArray(typedObj["value"]) - ) - }`, - }, - { options: { exportAll: true } } -) - -testProcessProject( - 'generated type guards for nested arrays', - { - 'test.ts': ` - export type Foo = { - value: Array<{ - value: Array - }> - } - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { Foo } from "./test"; - - export function isFoo(obj: unknown): obj is Foo { - const typedObj = obj as Foo - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - Array.isArray(typedObj["value"]) && - typedObj["value"].every((e: any) => - (e !== null && - typeof e === "object" || - typeof e === "function") && - Array.isArray(e["value"]) && - e["value"].every((e: any) => - typeof e === "number" - ) - ) - ) - }`, - }, - { options: { exportAll: true } } -) - -testProcessProject( - 'type that is an alias to an interface has a different typeguard name', - { - 'test.ts': ` - export interface TestType { - [index: any]: string - } - export type SecondaryTestType = TestType - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { TestType, SecondaryTestType } from "./test"; - - export function isTestType(obj: unknown): obj is TestType { - const typedObj = obj as TestType - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - Object.entries(typedObj) - .every(([_key, value]) => (typeof value === "string")) - ) - } - - export function isSecondaryTestType(obj: unknown): obj is SecondaryTestType { - const typedObj = obj as SecondaryTestType - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - Object.entries(typedObj) - .every(([_key, value]) => (typeof value === "string")) - ) - } - `, - }, - { options: { exportAll: true } } -) - -testProcessProject( - 'adds type guard import to source file and also exports', - { - // NOTE: This file is not automatically cleaned up with `formatText` after - // being modified so it requires this funky indentation to ensure that it is - // conforms to ts-morph's formatting. - 'test.ts': ` -/** @see {isEmpty} ts-auto-guard:type-guard */ -export interface Empty { } -`, - }, - { - 'test.ts': ` - import * as CustomGuardAlias from "./test.guard"; - - /** @see {isEmpty} ts-auto-guard:type-guard */ - export interface Empty {} - export { CustomGuardAlias };`, - 'test.guard.ts': ` - import { Empty } from "./test"; - - export function isEmpty(obj: unknown): obj is Empty { - const typedObj = obj as Empty - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") - ) - }`, - }, - { options: { importGuards: 'CustomGuardAlias' } } -) - -testProcessProject( - 'imports and uses generated type guard if the type is used in another file', - { - 'test.ts': ` - /** @see {isTestType} ts-auto-guard:type-guard */ - export interface TestType { - someKey: string | number - } - `, - 'test-list.ts': ` - import { TestType } from './test' - - /** @see {isTestTypeList} ts-auto-guard:type-guard */ - export type TestTypeList = Array - `, - }, - { - 'test.ts': null, - 'test-list.ts': null, - 'test-list.guard.ts': ` - import { isTestType } from "./test.guard"; - import { TestTypeList } from "./test-list"; - - export function isTestTypeList(obj: unknown): obj is TestTypeList { - const typedObj = obj as TestTypeList - return ( - Array.isArray(typedObj) && - typedObj.every((e: any) => - isTestType(e) as boolean - ) - ) - } - `, - 'test.guard.ts': ` - import { TestType } from "./test"; - - export function isTestType(obj: unknown): obj is TestType { - const typedObj = obj as TestType - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - (typeof typedObj["someKey"] === "string" || - typeof typedObj["someKey"] === "number") - ) + t.error(result.error, 'UglifyJS should succeed') + sourceText = result.code + } else { + expectedFile.formatText() + sourceText = sourceFile.getText() } - `, - } -) - -testProcessProject( - 'generates type guards for dynamic object keys, including when mixed with static keys', - { - 'test.ts': ` - /** @see {isTestType} ts-auto-guard:type-guard */ - export interface TestType { - someKey: "some" | "key" - [index: string]: "dynamic" | "string" - [index: number]: "also-dynamic" | "number" - } - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { TestType } from "./test"; - - export function isTestType(obj: unknown): obj is TestType { - const typedObj = obj as TestType - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - (typedObj["someKey"] === "some" || - typedObj["someKey"] === "key") && - Object.entries(typedObj) - .filter(([key]) => !["someKey"].includes(key)) - .every(([key, value]) => ((value === "string" || - value === "dynamic") && - typeof key === "string" || - (value === "number" || - value === "also-dynamic") && - typeof key === "number")) - ) - } - `, - } -) -testProcessProject( - 'generates type guards for Record types', - { - 'test.ts': ` - /** @see {isTestType} ts-auto-guard:type-guard */ - export type TestType = Record - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { TestType } from "./test"; - - export function isTestType(obj: unknown): obj is TestType { - const typedObj = obj as TestType - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - Object.entries(typedObj) - .every(([key, value]) => ((value === "string" || - value === "dynamic") && - typeof key === "string")) - ) + const expectedText = expectedFile.getText() + t.equal(sourceText, expectedText, `${filePath} should match`) } - `, - } -) - -testProcessProject( - 'prefixes value with underscore if it goes unused', - { - 'test.ts': ` - /** @see {isTestType} ts-auto-guard:type-guard */ - export interface TestType { - [index: string]: any - } - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { TestType } from "./test"; - - export function isTestType(obj: unknown): obj is TestType { - const typedObj = obj as TestType - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - Object.entries(typedObj) - .every(([key, _value]) => (typeof key === "string")) - ) - } - `, - } -) - -testProcessProject( - 'prefixes key with underscore if it goes unused', - { - 'test.ts': ` - /** @see {isTestType} ts-auto-guard:type-guard */ - export interface TestType { - [index: any]: string - } - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { TestType } from "./test"; - - export function isTestType(obj: unknown): obj is TestType { - const typedObj = obj as TestType - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - Object.entries(typedObj) - .every(([_key, value]) => (typeof value === "string")) - ) - } - `, - } -) - -testProcessProject( - 'Does not generate empty guard files', - { - 'test.ts': '', - }, - { 'test.ts': null } -) - -testProcessProject( - 'Deals with unknown type as it would any', - { - 'test.ts': ` - /** @see {isTestType} ts-auto-guard:type-guard */ - export interface TestType { - [index: string]: unknown - } - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { TestType } from "./test"; - - export function isTestType(obj: unknown): obj is TestType { - const typedObj = obj as TestType - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - Object.entries(typedObj) - .every(([key, _value]) => (typeof key === "string")) - ) - } - `, - } -) - -testProcessProject( - 'Deals with unknown type as it would any', - { - 'test.ts': ` - /** @see {isTestType} ts-auto-guard:type-guard */ - export interface TestType { - test: unknown - } - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { TestType } from "./test"; - - export function isTestType(obj: unknown): obj is TestType { - const typedObj = obj as TestType - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") - ) - } - `, - } -) - -testProcessProject( - 'Check if any callable properties is a function', - // should also emit a warning about how it is not possible to check function type at runtime. - { - 'test.ts': ` - /** @see {isTestType} ts-auto-guard:type-guard */ - export interface TestType { - test: (() => void) - // ts-auto-guard-suppress function-type - test2(someArg: number): boolean - // some other comments - test3: { - (someArg: string): number - test3Arg: number; - } - } - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { TestType } from "./test"; - - export function isTestType(obj: unknown): obj is TestType { - const typedObj = obj as TestType - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["test"] === "function" && - typeof typedObj["test3"] === "function" && - typeof typedObj["test3"]["test3Arg"] === "number" && - typeof typedObj["test2"] === "function" - ) - } - `, - } -) - -testProcessProject( - 'Check if callable interface is a function', - // should also emit a warning about how it is not possible to check function type at runtime. - { - 'test.ts': ` - /** @see {isTestType} ts-auto-guard:type-guard */ - export interface TestType { - (someArg: string): number - arg: number; - } - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { TestType } from "./test"; - - export function isTestType(obj: unknown): obj is TestType { - const typedObj = obj as TestType - return ( - typeof typedObj === "function" && - typeof typedObj["arg"] === "number" - ) - } - `, - } -) - -testProcessProject( - 'generated type guards for intersection type', - { - 'test.ts': ` - export type X = { foo: number } & { bar: string } - `, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { X } from "./test"; - - export function isX(obj: unknown): obj is X { - const typedObj = obj as X - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["foo"] === "number" && - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - typeof typedObj["bar"] === "string" - ) - }`, - }, - { options: { exportAll: true } } -) - -testProcessProject( - 'generates tuples', - { - 'test.ts': ` - export interface A { - b: [number] - }`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { A } from "./test"; - - export function isA(obj: unknown): obj is A { - const typedObj = obj as A - return ( - (typedObj !== null && - typeof typedObj === "object" || - typeof typedObj === "function") && - Array.isArray(typedObj["b"]) && - typeof typedObj["b"][0] === "number" - ) - }`, - }, - { options: { exportAll: true } } -) - -testProcessProject( - 'skips checking any type in array', - { - 'test.ts': `export type A = any[]`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { A } from "./test"; - - export function isA(obj: unknown): obj is A { - const typedObj = obj as A - return ( - Array.isArray(typedObj) - ) - }`, - }, - { options: { exportAll: true } } -) - -testProcessProject( - 'works for any type', - { - 'test.ts': `export type A = any`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { A } from "./test"; - - export function isA(obj: unknown): obj is A { - const typedObj = obj as A - return ( - true - ) - }`, - }, - { options: { exportAll: true } } -) - -testProcessProject( - 'works for unknown type', - { - 'test.ts': `export type A = unknown`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { A } from "./test"; - - export function isA(obj: unknown): obj is A { - const typedObj = obj as A - return ( - true - ) - }`, - }, - { options: { exportAll: true } } -) - -testProcessProject( - 'any and unknown work in union types', - { - 'test.ts': ` - type anyType = any - type unknownType = unknown - - export type AnyOrString = string | anyType - export type UnknownOrString = string | unknownType - export type AnyOrUnknownOrString = string | anyType | unknownType`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { AnyOrString, UnknownOrString, AnyOrUnknownOrString } from "./test"; - - export function isAnyOrString(obj: unknown): obj is AnyOrString { - const typedObj = obj as AnyOrString - return ( - true - ) } - - export function isUnknownOrString(obj: unknown): obj is UnknownOrString { - const typedObj = obj as UnknownOrString - return ( - true - ) + for (const filePath of expectedFilenames) { + t.fail(`${filePath} not found`) } - - export function isAnyOrUnknownOrString(obj: unknown): obj is AnyOrUnknownOrString { - const typedObj = obj as AnyOrUnknownOrString - return ( - true - ) - }`, - }, - { options: { exportAll: true } } -) - -testProcessProject( - 'any and unknown work in interesction types', - { - 'test.ts': ` - type anyType = any - type unknownType = unknown - - export type AnyAndString = string & anyType - export type UnknownAndString = string & unknownType - export type AnyAndUnknownAndString = string & anyType & unknownType`, - }, - { - 'test.ts': null, - 'test.guard.ts': ` - import { AnyAndString, UnknownAndString, AnyAndUnknownAndString } from "./test"; - - export function isAnyAndString(obj: unknown): obj is AnyAndString { - const typedObj = obj as AnyAndString - return ( - true - ) - } - - export function isUnknownAndString(obj: unknown): obj is UnknownAndString { - const typedObj = obj as UnknownAndString - return ( - typeof typedObj === "string" - ) - } - - export function isAnyAndUnknownAndString(obj: unknown): obj is AnyAndUnknownAndString { - const typedObj = obj as AnyAndUnknownAndString - return ( - true - ) - }`, - }, - { options: { exportAll: true } } -) + t.end() + }) +} From f05debd02c2aed2c1c5641d0a97d9428f3de3231 Mon Sep 17 00:00:00 2001 From: Timur Seitosmanov Date: Tue, 11 Oct 2022 15:17:59 +0200 Subject: [PATCH 4/4] Reformat, add .test suffix, restore test script in package.json --- package.json | 2 +- ...type_guard_import_to_source_file_and_also_exports.test.ts} | 4 ++-- ...s_the_name_of_the_guard_file_file_to_be_specified.test.ts} | 4 ++-- ....ts => any_and_unknown_work_in_interesction_types.test.ts} | 4 ++-- ...n_types.ts => any_and_unknown_work_in_union_types.test.ts} | 4 ++-- ...=> check_if_any_callable_properties_is_a_function.test.ts} | 4 ++-- ...n.ts => check_if_callable_interface_is_a_function.test.ts} | 4 ++-- ...ult_export.ts => correctly_handles_default_export.test.ts} | 4 ++-- ...any.ts => deals_with_unknown_type_as_it_would_any.test.ts} | 4 ++-- ...d_files.ts => does_not_generate_empty_guard_files.test.ts} | 4 ++-- ...ot_touch_guardts_files_that_are_not_autogenerated.test.ts} | 4 ++-- ...any.ts => generated_type_guards_for_arrays_of_any.test.ts} | 4 ++-- ...=> generated_type_guards_for_discriminated_unions.test.ts} | 4 ++-- ...s_for_enums.ts => generated_type_guards_for_enums.test.ts} | 4 ++-- ...ts => generated_type_guards_for_intersection_type.test.ts} | 4 ++-- ...ays.ts => generated_type_guards_for_nested_arrays.test.ts} | 4 ++-- ...type_guards_for_numeric_enums_in_optional_records.test.ts} | 4 ++-- ..._short_circuit_are_correctly_stripped_by_UglifyJS.test.ts} | 4 ++-- .../{generates_tuples.ts => generates_tuples.test.ts} | 4 ++-- ...generates_type_guards_for_JSDoc_see_with_link_tag.test.ts} | 4 ++-- ..._type.ts => generates_type_guards_for_a_Pick_type.test.ts} | 0 ... generates_type_guards_for_an_object_literal_type.test.ts} | 4 ++-- ...r_boolean.ts => generates_type_guards_for_boolean.test.ts} | 4 ++-- ...bject_keys,_including_when_mixed_with_static_keys.test.ts} | 4 ++-- ...type_guards_for_empty_object_if_exportAll_is_true.test.ts} | 4 ++-- ...s_type_guards_for_interface_extending_object_type.test.ts} | 4 ++-- ...r_interface_extending_object_type_with_type_guard.test.ts} | 4 ++-- ...pe_guards_for_interface_extending_other_interface.test.ts} | 4 ++-- ...terface_extending_other_interface_with_type_guard.test.ts} | 4 ++-- ...rds_for_interface_properties_with_numerical_names.test.ts} | 4 ++-- ..._for_interface_property_with_empty_string_as_name.test.ts} | 4 ++-- ...tes_type_guards_for_interface_with_optional_field.test.ts} | 4 ++-- ...ypes.ts => generates_type_guards_for_mapped_types.test.ts} | 4 ++-- ....ts => generates_type_guards_for_nested_interface.test.ts} | 4 ++-- ..._type_guards_for_nested_interface_with_type_guard.test.ts} | 4 ++-- ...e_guards_for_property_with_non_alphanumeric_name_.test.ts} | 0 ...ypes.ts => generates_type_guards_for_record_types.test.ts} | 4 ++-- ...s.ts => generates_type_guards_for_recursive_types.test.ts} | 4 ++-- ....ts => generates_type_guards_for_simple_interface.test.ts} | 4 ++-- ...e_guards_for_type_properties_with_numerical_names.test.ts} | 4 ++-- ...uards_for_type_property_with_empty_string_as_name.test.ts} | 4 ++-- ....ts => generates_type_guards_with_a_short_circuit.test.ts} | 4 ++-- ...ed_type_guard_if_the_type_is_used_in_another_file.test.ts} | 4 ++-- ...=> prefixes_key_with_underscore_if_it_goes_unused.test.ts} | 4 ++-- ... prefixes_value_with_underscore_if_it_goes_unused.test.ts} | 4 ++-- ...ardFileNames.ts => rejects_invalid_guardFileNames.test.ts} | 0 ...s_correct_guardts_files_when_guardFileName_is_set.test.ts} | 4 ++-- ...uardts_files.ts => removes_existing_guardts_files.test.ts} | 4 ++-- .../features/{show_debug_info.ts => show_debug_info.test.ts} | 4 ++-- ...e_in_array.ts => skips_checking_any_type_in_array.test.ts} | 4 ++-- ...as_to_an_interface_has_a_different_typeguard_name.test.ts} | 4 ++-- ...correct_import_file_name_if_guard_file_is_renamed.test.ts} | 4 ++-- .../{works_for_any_type.ts => works_for_any_type.test.ts} | 4 ++-- ...rks_for_unknown_type.ts => works_for_unknown_type.test.ts} | 4 ++-- tests/{import.ts => import.test.ts} | 0 tsconfig.json | 3 ++- 56 files changed, 103 insertions(+), 102 deletions(-) rename tests/features/{adds_type_guard_import_to_source_file_and_also_exports.ts => adds_type_guard_import_to_source_file_and_also_exports.test.ts} (94%) rename tests/features/{allows_the_name_of_the_guard_file_file_to_be_specified.ts => allows_the_name_of_the_guard_file_file_to_be_specified.test.ts} (93%) rename tests/features/{any_and_unknown_work_in_interesction_types.ts => any_and_unknown_work_in_interesction_types.test.ts} (95%) rename tests/features/{any_and_unknown_work_in_union_types.ts => any_and_unknown_work_in_union_types.test.ts} (95%) rename tests/features/{check_if_any_callable_properties_is_a_function.ts => check_if_any_callable_properties_is_a_function.test.ts} (95%) rename tests/features/{check_if_callable_interface_is_a_function.ts => check_if_callable_interface_is_a_function.test.ts} (93%) rename tests/features/{correctly_handles_default_export.ts => correctly_handles_default_export.test.ts} (92%) rename tests/features/{deals_with_unknown_type_as_it_would_any.ts => deals_with_unknown_type_as_it_would_any.test.ts} (93%) rename tests/features/{does_not_generate_empty_guard_files.ts => does_not_generate_empty_guard_files.test.ts} (68%) rename tests/features/{does_not_touch_guardts_files_that_are_not_autogenerated.ts => does_not_touch_guardts_files_that_are_not_autogenerated.test.ts} (75%) rename tests/features/{generated_type_guards_for_arrays_of_any.ts => generated_type_guards_for_arrays_of_any.test.ts} (92%) rename tests/features/{generated_type_guards_for_discriminated_unions.ts => generated_type_guards_for_discriminated_unions.test.ts} (94%) rename tests/features/{generated_type_guards_for_enums.ts => generated_type_guards_for_enums.test.ts} (91%) rename tests/features/{generated_type_guards_for_intersection_type.ts => generated_type_guards_for_intersection_type.test.ts} (93%) rename tests/features/{generated_type_guards_for_nested_arrays.ts => generated_type_guards_for_nested_arrays.test.ts} (95%) rename tests/features/{generated_type_guards_for_numeric_enums_in_optional_records.ts => generated_type_guards_for_numeric_enums_in_optional_records.test.ts} (96%) rename tests/features/{generated_type_guards_with_a_short_circuit_are_correctly_stripped_by_UglifyJS.ts => generated_type_guards_with_a_short_circuit_are_correctly_stripped_by_UglifyJS.test.ts} (92%) rename tests/features/{generates_tuples.ts => generates_tuples.test.ts} (91%) rename tests/features/{generates_type_guards_for_JSDoc_see_with_link_tag.ts => generates_type_guards_for_JSDoc_see_with_link_tag.test.ts} (89%) rename tests/features/{generates_type_guards_for_a_Pick_type.ts => generates_type_guards_for_a_Pick_type.test.ts} (100%) rename tests/features/{generates_type_guards_for_an_object_literal_type.ts => generates_type_guards_for_an_object_literal_type.test.ts} (92%) rename tests/features/{generates_type_guards_for_boolean.ts => generates_type_guards_for_boolean.test.ts} (89%) rename tests/features/{generates_type_guards_for_dynamic_object_keys,_including_when_mixed_with_static_keys.ts => generates_type_guards_for_dynamic_object_keys,_including_when_mixed_with_static_keys.test.ts} (96%) rename tests/features/{generates_type_guards_for_empty_object_if_exportAll_is_true.ts => generates_type_guards_for_empty_object_if_exportAll_is_true.test.ts} (91%) rename tests/features/{generates_type_guards_for_interface_extending_object_type.ts => generates_type_guards_for_interface_extending_object_type.test.ts} (93%) rename tests/features/{generates_type_guards_for_interface_extending_object_type_with_type_guard.ts => generates_type_guards_for_interface_extending_object_type_with_type_guard.test.ts} (94%) rename tests/features/{generates_type_guards_for_interface_extending_other_interface.ts => generates_type_guards_for_interface_extending_other_interface.test.ts} (93%) rename tests/features/{generates_type_guards_for_interface_extending_other_interface_with_type_guard.ts => generates_type_guards_for_interface_extending_other_interface_with_type_guard.test.ts} (94%) rename tests/features/{generates_type_guards_for_interface_properties_with_numerical_names.ts => generates_type_guards_for_interface_properties_with_numerical_names.test.ts} (92%) rename tests/features/{generates_type_guards_for_interface_property_with_empty_string_as_name.ts => generates_type_guards_for_interface_property_with_empty_string_as_name.test.ts} (92%) rename tests/features/{generates_type_guards_for_interface_with_optional_field.ts => generates_type_guards_for_interface_with_optional_field.test.ts} (94%) rename tests/features/{generates_type_guards_for_mapped_types.ts => generates_type_guards_for_mapped_types.test.ts} (96%) rename tests/features/{generates_type_guards_for_nested_interface.ts => generates_type_guards_for_nested_interface.test.ts} (93%) rename tests/features/{generates_type_guards_for_nested_interface_with_type_guard.ts => generates_type_guards_for_nested_interface_with_type_guard.test.ts} (95%) rename tests/features/{generates_type_guards_for_property_with_non_alphanumeric_name_.ts => generates_type_guards_for_property_with_non_alphanumeric_name_.test.ts} (100%) rename tests/features/{generates_type_guards_for_record_types.ts => generates_type_guards_for_record_types.test.ts} (94%) rename tests/features/{generates_type_guards_for_recursive_types.ts => generates_type_guards_for_recursive_types.test.ts} (97%) rename tests/features/{generates_type_guards_for_simple_interface.ts => generates_type_guards_for_simple_interface.test.ts} (92%) rename tests/features/{generates_type_guards_for_type_properties_with_numerical_names.ts => generates_type_guards_for_type_properties_with_numerical_names.test.ts} (92%) rename tests/features/{generates_type_guards_for_type_property_with_empty_string_as_name.ts => generates_type_guards_for_type_property_with_empty_string_as_name.test.ts} (92%) rename tests/features/{generates_type_guards_with_a_short_circuit.ts => generates_type_guards_with_a_short_circuit.test.ts} (93%) rename tests/features/{imports_and_uses_generated_type_guard_if_the_type_is_used_in_another_file.ts => imports_and_uses_generated_type_guard_if_the_type_is_used_in_another_file.test.ts} (96%) rename tests/features/{prefixes_key_with_underscore_if_it_goes_unused.ts => prefixes_key_with_underscore_if_it_goes_unused.test.ts} (93%) rename tests/features/{prefixes_value_with_underscore_if_it_goes_unused.ts => prefixes_value_with_underscore_if_it_goes_unused.test.ts} (93%) rename tests/features/{rejects_invalid_guardFileNames.ts => rejects_invalid_guardFileNames.test.ts} (100%) rename tests/features/{removes_correct_guardts_files_when_guardFileName_is_set.ts => removes_correct_guardts_files_when_guardFileName_is_set.test.ts} (86%) rename tests/features/{removes_existing_guardts_files.ts => removes_existing_guardts_files.test.ts} (75%) rename tests/features/{show_debug_info.ts => show_debug_info.test.ts} (97%) rename tests/features/{skips_checking_any_type_in_array.ts => skips_checking_any_type_in_array.test.ts} (88%) rename tests/features/{type_that_is_an_alias_to_an_interface_has_a_different_typeguard_name.ts => type_that_is_an_alias_to_an_interface_has_a_different_typeguard_name.test.ts} (96%) rename tests/features/{uses_correct_import_file_name_if_guard_file_is_renamed.ts => uses_correct_import_file_name_if_guard_file_is_renamed.test.ts} (93%) rename tests/features/{works_for_any_type.ts => works_for_any_type.test.ts} (87%) rename tests/features/{works_for_unknown_type.ts => works_for_unknown_type.test.ts} (87%) rename tests/{import.ts => import.test.ts} (100%) diff --git a/package.json b/package.json index cf97e1c..3aae526 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "repository": "github:rhys-vdw/ts-auto-guard", "main": "lib/index.js", "scripts": { - "test": "tape -r ts-node/register tests/**/*.ts", + "test": "cross-env NODE_ENV=test && npm run lint && npm run format:check && tape -r ts-node/register tests/**/*.test.ts | tap-diff", "build": "tsc", "prepare": "npm run build", "lint": "eslint .", diff --git a/tests/features/adds_type_guard_import_to_source_file_and_also_exports.ts b/tests/features/adds_type_guard_import_to_source_file_and_also_exports.test.ts similarity index 94% rename from tests/features/adds_type_guard_import_to_source_file_and_also_exports.ts rename to tests/features/adds_type_guard_import_to_source_file_and_also_exports.test.ts index 8ab0229..27e1771 100644 --- a/tests/features/adds_type_guard_import_to_source_file_and_also_exports.ts +++ b/tests/features/adds_type_guard_import_to_source_file_and_also_exports.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'adds type guard import to source file and also exports', @@ -31,4 +31,4 @@ export interface Empty { } }`, }, { options: { importGuards: 'CustomGuardAlias' } } -) \ No newline at end of file +) diff --git a/tests/features/allows_the_name_of_the_guard_file_file_to_be_specified.ts b/tests/features/allows_the_name_of_the_guard_file_file_to_be_specified.test.ts similarity index 93% rename from tests/features/allows_the_name_of_the_guard_file_file_to_be_specified.ts rename to tests/features/allows_the_name_of_the_guard_file_file_to_be_specified.test.ts index 989393f..740e236 100644 --- a/tests/features/allows_the_name_of_the_guard_file_file_to_be_specified.ts +++ b/tests/features/allows_the_name_of_the_guard_file_file_to_be_specified.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'allows the name of the guard file file to be specified', @@ -31,4 +31,4 @@ testProcessProject( guardFileName: 'debug', }, } -) \ No newline at end of file +) diff --git a/tests/features/any_and_unknown_work_in_interesction_types.ts b/tests/features/any_and_unknown_work_in_interesction_types.test.ts similarity index 95% rename from tests/features/any_and_unknown_work_in_interesction_types.ts rename to tests/features/any_and_unknown_work_in_interesction_types.test.ts index 07ee4c6..16f04fb 100644 --- a/tests/features/any_and_unknown_work_in_interesction_types.ts +++ b/tests/features/any_and_unknown_work_in_interesction_types.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'any and unknown work in interesction types', @@ -38,4 +38,4 @@ testProcessProject( }`, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/features/any_and_unknown_work_in_union_types.ts b/tests/features/any_and_unknown_work_in_union_types.test.ts similarity index 95% rename from tests/features/any_and_unknown_work_in_union_types.ts rename to tests/features/any_and_unknown_work_in_union_types.test.ts index e7295f8..6e4d11c 100644 --- a/tests/features/any_and_unknown_work_in_union_types.ts +++ b/tests/features/any_and_unknown_work_in_union_types.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'any and unknown work in union types', @@ -38,4 +38,4 @@ testProcessProject( }`, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/features/check_if_any_callable_properties_is_a_function.ts b/tests/features/check_if_any_callable_properties_is_a_function.test.ts similarity index 95% rename from tests/features/check_if_any_callable_properties_is_a_function.ts rename to tests/features/check_if_any_callable_properties_is_a_function.test.ts index 594d7ee..b58c4e9 100644 --- a/tests/features/check_if_any_callable_properties_is_a_function.ts +++ b/tests/features/check_if_any_callable_properties_is_a_function.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'Check if any callable properties is a function', @@ -37,4 +37,4 @@ testProcessProject( } `, } -) \ No newline at end of file +) diff --git a/tests/features/check_if_callable_interface_is_a_function.ts b/tests/features/check_if_callable_interface_is_a_function.test.ts similarity index 93% rename from tests/features/check_if_callable_interface_is_a_function.ts rename to tests/features/check_if_callable_interface_is_a_function.test.ts index 6fc6374..043098c 100644 --- a/tests/features/check_if_callable_interface_is_a_function.ts +++ b/tests/features/check_if_callable_interface_is_a_function.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'Check if callable interface is a function', @@ -26,4 +26,4 @@ testProcessProject( } `, } -) \ No newline at end of file +) diff --git a/tests/features/correctly_handles_default_export.ts b/tests/features/correctly_handles_default_export.test.ts similarity index 92% rename from tests/features/correctly_handles_default_export.ts rename to tests/features/correctly_handles_default_export.test.ts index 29f16b8..aaf8167 100644 --- a/tests/features/correctly_handles_default_export.ts +++ b/tests/features/correctly_handles_default_export.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'correctly handles default export', @@ -28,4 +28,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/deals_with_unknown_type_as_it_would_any.ts b/tests/features/deals_with_unknown_type_as_it_would_any.test.ts similarity index 93% rename from tests/features/deals_with_unknown_type_as_it_would_any.ts rename to tests/features/deals_with_unknown_type_as_it_would_any.test.ts index 32c500d..64ad11f 100644 --- a/tests/features/deals_with_unknown_type_as_it_would_any.ts +++ b/tests/features/deals_with_unknown_type_as_it_would_any.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'Deals with unknown type as it would any', @@ -27,4 +27,4 @@ testProcessProject( } `, } -) \ No newline at end of file +) diff --git a/tests/features/does_not_generate_empty_guard_files.ts b/tests/features/does_not_generate_empty_guard_files.test.ts similarity index 68% rename from tests/features/does_not_generate_empty_guard_files.ts rename to tests/features/does_not_generate_empty_guard_files.test.ts index f3f0932..03ac64d 100644 --- a/tests/features/does_not_generate_empty_guard_files.ts +++ b/tests/features/does_not_generate_empty_guard_files.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'Does not generate empty guard files', @@ -6,4 +6,4 @@ testProcessProject( 'test.ts': '', }, { 'test.ts': null } -) \ No newline at end of file +) diff --git a/tests/features/does_not_touch_guardts_files_that_are_not_autogenerated.ts b/tests/features/does_not_touch_guardts_files_that_are_not_autogenerated.test.ts similarity index 75% rename from tests/features/does_not_touch_guardts_files_that_are_not_autogenerated.ts rename to tests/features/does_not_touch_guardts_files_that_are_not_autogenerated.test.ts index 7b2d320..3d79cd1 100644 --- a/tests/features/does_not_touch_guardts_files_that_are_not_autogenerated.ts +++ b/tests/features/does_not_touch_guardts_files_that_are_not_autogenerated.test.ts @@ -1,7 +1,7 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'does not touch .guard.ts files that are not autogenerated', { 'test.guard.ts': `alert("hello")` }, { 'test.guard.ts': null } -) \ No newline at end of file +) diff --git a/tests/features/generated_type_guards_for_arrays_of_any.ts b/tests/features/generated_type_guards_for_arrays_of_any.test.ts similarity index 92% rename from tests/features/generated_type_guards_for_arrays_of_any.ts rename to tests/features/generated_type_guards_for_arrays_of_any.test.ts index e55ffa8..308eef1 100644 --- a/tests/features/generated_type_guards_for_arrays_of_any.ts +++ b/tests/features/generated_type_guards_for_arrays_of_any.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generated type guards for arrays of any', @@ -25,4 +25,4 @@ testProcessProject( }`, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/features/generated_type_guards_for_discriminated_unions.ts b/tests/features/generated_type_guards_for_discriminated_unions.test.ts similarity index 94% rename from tests/features/generated_type_guards_for_discriminated_unions.ts rename to tests/features/generated_type_guards_for_discriminated_unions.test.ts index 37a0c89..80b71bc 100644 --- a/tests/features/generated_type_guards_for_discriminated_unions.ts +++ b/tests/features/generated_type_guards_for_discriminated_unions.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generated type guards for discriminated unions', @@ -29,4 +29,4 @@ testProcessProject( }`, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/features/generated_type_guards_for_enums.ts b/tests/features/generated_type_guards_for_enums.test.ts similarity index 91% rename from tests/features/generated_type_guards_for_enums.ts rename to tests/features/generated_type_guards_for_enums.test.ts index 34c793d..d79267b 100644 --- a/tests/features/generated_type_guards_for_enums.ts +++ b/tests/features/generated_type_guards_for_enums.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generated type guards for enums', @@ -25,4 +25,4 @@ testProcessProject( }`, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/features/generated_type_guards_for_intersection_type.ts b/tests/features/generated_type_guards_for_intersection_type.test.ts similarity index 93% rename from tests/features/generated_type_guards_for_intersection_type.ts rename to tests/features/generated_type_guards_for_intersection_type.test.ts index ee868b7..5a3be10 100644 --- a/tests/features/generated_type_guards_for_intersection_type.ts +++ b/tests/features/generated_type_guards_for_intersection_type.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generated type guards for intersection type', @@ -27,4 +27,4 @@ testProcessProject( }`, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/features/generated_type_guards_for_nested_arrays.ts b/tests/features/generated_type_guards_for_nested_arrays.test.ts similarity index 95% rename from tests/features/generated_type_guards_for_nested_arrays.ts rename to tests/features/generated_type_guards_for_nested_arrays.test.ts index 71fd728..73803cc 100644 --- a/tests/features/generated_type_guards_for_nested_arrays.ts +++ b/tests/features/generated_type_guards_for_nested_arrays.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generated type guards for nested arrays', @@ -36,4 +36,4 @@ testProcessProject( }`, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/features/generated_type_guards_for_numeric_enums_in_optional_records.ts b/tests/features/generated_type_guards_for_numeric_enums_in_optional_records.test.ts similarity index 96% rename from tests/features/generated_type_guards_for_numeric_enums_in_optional_records.ts rename to tests/features/generated_type_guards_for_numeric_enums_in_optional_records.test.ts index 0514021..61b6d9a 100644 --- a/tests/features/generated_type_guards_for_numeric_enums_in_optional_records.ts +++ b/tests/features/generated_type_guards_for_numeric_enums_in_optional_records.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generated type guards for numeric enums in optional records', @@ -46,4 +46,4 @@ testProcessProject( }`, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/features/generated_type_guards_with_a_short_circuit_are_correctly_stripped_by_UglifyJS.ts b/tests/features/generated_type_guards_with_a_short_circuit_are_correctly_stripped_by_UglifyJS.test.ts similarity index 92% rename from tests/features/generated_type_guards_with_a_short_circuit_are_correctly_stripped_by_UglifyJS.ts rename to tests/features/generated_type_guards_with_a_short_circuit_are_correctly_stripped_by_UglifyJS.test.ts index 9e62b1f..a6ef546 100644 --- a/tests/features/generated_type_guards_with_a_short_circuit_are_correctly_stripped_by_UglifyJS.ts +++ b/tests/features/generated_type_guards_with_a_short_circuit_are_correctly_stripped_by_UglifyJS.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generated type guards with a short circuit are correctly stripped by UglifyJS', @@ -21,4 +21,4 @@ testProcessProject( }, options: { shortCircuitCondition: 'DEBUG', debug: false }, } -) \ No newline at end of file +) diff --git a/tests/features/generates_tuples.ts b/tests/features/generates_tuples.test.ts similarity index 91% rename from tests/features/generates_tuples.ts rename to tests/features/generates_tuples.test.ts index 1678145..c76cc09 100644 --- a/tests/features/generates_tuples.ts +++ b/tests/features/generates_tuples.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates tuples', @@ -25,4 +25,4 @@ testProcessProject( }`, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_JSDoc_see_with_link_tag.ts b/tests/features/generates_type_guards_for_JSDoc_see_with_link_tag.test.ts similarity index 89% rename from tests/features/generates_type_guards_for_JSDoc_see_with_link_tag.ts rename to tests/features/generates_type_guards_for_JSDoc_see_with_link_tag.test.ts index f6ffff3..5c4c54c 100644 --- a/tests/features/generates_type_guards_for_JSDoc_see_with_link_tag.ts +++ b/tests/features/generates_type_guards_for_JSDoc_see_with_link_tag.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for JSDoc @see with @link tag', @@ -19,4 +19,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_a_Pick_type.ts b/tests/features/generates_type_guards_for_a_Pick_type.test.ts similarity index 100% rename from tests/features/generates_type_guards_for_a_Pick_type.ts rename to tests/features/generates_type_guards_for_a_Pick_type.test.ts diff --git a/tests/features/generates_type_guards_for_an_object_literal_type.ts b/tests/features/generates_type_guards_for_an_object_literal_type.test.ts similarity index 92% rename from tests/features/generates_type_guards_for_an_object_literal_type.ts rename to tests/features/generates_type_guards_for_an_object_literal_type.test.ts index 7792f17..76044cd 100644 --- a/tests/features/generates_type_guards_for_an_object_literal_type.ts +++ b/tests/features/generates_type_guards_for_an_object_literal_type.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for an object literal type', @@ -24,4 +24,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_boolean.ts b/tests/features/generates_type_guards_for_boolean.test.ts similarity index 89% rename from tests/features/generates_type_guards_for_boolean.ts rename to tests/features/generates_type_guards_for_boolean.test.ts index 6fbc6cc..50e26a8 100644 --- a/tests/features/generates_type_guards_for_boolean.ts +++ b/tests/features/generates_type_guards_for_boolean.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for boolean', @@ -19,4 +19,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_dynamic_object_keys,_including_when_mixed_with_static_keys.ts b/tests/features/generates_type_guards_for_dynamic_object_keys,_including_when_mixed_with_static_keys.test.ts similarity index 96% rename from tests/features/generates_type_guards_for_dynamic_object_keys,_including_when_mixed_with_static_keys.ts rename to tests/features/generates_type_guards_for_dynamic_object_keys,_including_when_mixed_with_static_keys.test.ts index 0c33f65..be63363 100644 --- a/tests/features/generates_type_guards_for_dynamic_object_keys,_including_when_mixed_with_static_keys.ts +++ b/tests/features/generates_type_guards_for_dynamic_object_keys,_including_when_mixed_with_static_keys.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for dynamic object keys, including when mixed with static keys', @@ -37,4 +37,4 @@ testProcessProject( } `, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_empty_object_if_exportAll_is_true.ts b/tests/features/generates_type_guards_for_empty_object_if_exportAll_is_true.test.ts similarity index 91% rename from tests/features/generates_type_guards_for_empty_object_if_exportAll_is_true.ts rename to tests/features/generates_type_guards_for_empty_object_if_exportAll_is_true.test.ts index 2a3be23..08ab659 100644 --- a/tests/features/generates_type_guards_for_empty_object_if_exportAll_is_true.ts +++ b/tests/features/generates_type_guards_for_empty_object_if_exportAll_is_true.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for empty object if exportAll is true', @@ -21,4 +21,4 @@ testProcessProject( }`, }, { options: { exportAll: true, debug: false } } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_interface_extending_object_type.ts b/tests/features/generates_type_guards_for_interface_extending_object_type.test.ts similarity index 93% rename from tests/features/generates_type_guards_for_interface_extending_object_type.ts rename to tests/features/generates_type_guards_for_interface_extending_object_type.test.ts index 88df1d6..d72a58f 100644 --- a/tests/features/generates_type_guards_for_interface_extending_object_type.ts +++ b/tests/features/generates_type_guards_for_interface_extending_object_type.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for interface extending object type', @@ -29,4 +29,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_interface_extending_object_type_with_type_guard.ts b/tests/features/generates_type_guards_for_interface_extending_object_type_with_type_guard.test.ts similarity index 94% rename from tests/features/generates_type_guards_for_interface_extending_object_type_with_type_guard.ts rename to tests/features/generates_type_guards_for_interface_extending_object_type_with_type_guard.test.ts index 9439e54..efd5f0e 100644 --- a/tests/features/generates_type_guards_for_interface_extending_object_type_with_type_guard.ts +++ b/tests/features/generates_type_guards_for_interface_extending_object_type_with_type_guard.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for interface extending object type with type guard', @@ -37,4 +37,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_interface_extending_other_interface.ts b/tests/features/generates_type_guards_for_interface_extending_other_interface.test.ts similarity index 93% rename from tests/features/generates_type_guards_for_interface_extending_other_interface.ts rename to tests/features/generates_type_guards_for_interface_extending_other_interface.test.ts index c838e09..a61dfc9 100644 --- a/tests/features/generates_type_guards_for_interface_extending_other_interface.ts +++ b/tests/features/generates_type_guards_for_interface_extending_other_interface.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for interface extending other interface', @@ -29,4 +29,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_interface_extending_other_interface_with_type_guard.ts b/tests/features/generates_type_guards_for_interface_extending_other_interface_with_type_guard.test.ts similarity index 94% rename from tests/features/generates_type_guards_for_interface_extending_other_interface_with_type_guard.ts rename to tests/features/generates_type_guards_for_interface_extending_other_interface_with_type_guard.test.ts index 601b752..5c4d421 100644 --- a/tests/features/generates_type_guards_for_interface_extending_other_interface_with_type_guard.ts +++ b/tests/features/generates_type_guards_for_interface_extending_other_interface_with_type_guard.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for interface extending other interface with type guard', @@ -37,4 +37,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_interface_properties_with_numerical_names.ts b/tests/features/generates_type_guards_for_interface_properties_with_numerical_names.test.ts similarity index 92% rename from tests/features/generates_type_guards_for_interface_properties_with_numerical_names.ts rename to tests/features/generates_type_guards_for_interface_properties_with_numerical_names.test.ts index c00ddf8..bdbaa99 100644 --- a/tests/features/generates_type_guards_for_interface_properties_with_numerical_names.ts +++ b/tests/features/generates_type_guards_for_interface_properties_with_numerical_names.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for interface properties with numerical names', @@ -26,4 +26,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_interface_property_with_empty_string_as_name.ts b/tests/features/generates_type_guards_for_interface_property_with_empty_string_as_name.test.ts similarity index 92% rename from tests/features/generates_type_guards_for_interface_property_with_empty_string_as_name.ts rename to tests/features/generates_type_guards_for_interface_property_with_empty_string_as_name.test.ts index 1fcf797..2998221 100644 --- a/tests/features/generates_type_guards_for_interface_property_with_empty_string_as_name.ts +++ b/tests/features/generates_type_guards_for_interface_property_with_empty_string_as_name.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for interface property with empty string as name', @@ -24,4 +24,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_interface_with_optional_field.ts b/tests/features/generates_type_guards_for_interface_with_optional_field.test.ts similarity index 94% rename from tests/features/generates_type_guards_for_interface_with_optional_field.ts rename to tests/features/generates_type_guards_for_interface_with_optional_field.test.ts index b2d98bb..c1e4833 100644 --- a/tests/features/generates_type_guards_for_interface_with_optional_field.ts +++ b/tests/features/generates_type_guards_for_interface_with_optional_field.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for interface with optional field', @@ -31,4 +31,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_mapped_types.ts b/tests/features/generates_type_guards_for_mapped_types.test.ts similarity index 96% rename from tests/features/generates_type_guards_for_mapped_types.ts rename to tests/features/generates_type_guards_for_mapped_types.test.ts index 30ce555..dbfed5d 100644 --- a/tests/features/generates_type_guards_for_mapped_types.ts +++ b/tests/features/generates_type_guards_for_mapped_types.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for mapped types', @@ -50,4 +50,4 @@ testProcessProject( } `, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_nested_interface.ts b/tests/features/generates_type_guards_for_nested_interface.test.ts similarity index 93% rename from tests/features/generates_type_guards_for_nested_interface.ts rename to tests/features/generates_type_guards_for_nested_interface.test.ts index 01bced3..62f281e 100644 --- a/tests/features/generates_type_guards_for_nested_interface.ts +++ b/tests/features/generates_type_guards_for_nested_interface.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for nested interface', @@ -31,4 +31,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_nested_interface_with_type_guard.ts b/tests/features/generates_type_guards_for_nested_interface_with_type_guard.test.ts similarity index 95% rename from tests/features/generates_type_guards_for_nested_interface_with_type_guard.ts rename to tests/features/generates_type_guards_for_nested_interface_with_type_guard.test.ts index 439c883..895d4a0 100644 --- a/tests/features/generates_type_guards_for_nested_interface_with_type_guard.ts +++ b/tests/features/generates_type_guards_for_nested_interface_with_type_guard.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for nested interface with type guard', @@ -39,4 +39,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_property_with_non_alphanumeric_name_.ts b/tests/features/generates_type_guards_for_property_with_non_alphanumeric_name_.test.ts similarity index 100% rename from tests/features/generates_type_guards_for_property_with_non_alphanumeric_name_.ts rename to tests/features/generates_type_guards_for_property_with_non_alphanumeric_name_.test.ts diff --git a/tests/features/generates_type_guards_for_record_types.ts b/tests/features/generates_type_guards_for_record_types.test.ts similarity index 94% rename from tests/features/generates_type_guards_for_record_types.ts rename to tests/features/generates_type_guards_for_record_types.test.ts index 51c4c5c..4614b8f 100644 --- a/tests/features/generates_type_guards_for_record_types.ts +++ b/tests/features/generates_type_guards_for_record_types.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for Record types', @@ -27,4 +27,4 @@ testProcessProject( } `, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_recursive_types.ts b/tests/features/generates_type_guards_for_recursive_types.test.ts similarity index 97% rename from tests/features/generates_type_guards_for_recursive_types.ts rename to tests/features/generates_type_guards_for_recursive_types.test.ts index 99fc8be..81eb24c 100644 --- a/tests/features/generates_type_guards_for_recursive_types.ts +++ b/tests/features/generates_type_guards_for_recursive_types.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for recursive types', @@ -65,4 +65,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_simple_interface.ts b/tests/features/generates_type_guards_for_simple_interface.test.ts similarity index 92% rename from tests/features/generates_type_guards_for_simple_interface.ts rename to tests/features/generates_type_guards_for_simple_interface.test.ts index 8ad762b..a6560df 100644 --- a/tests/features/generates_type_guards_for_simple_interface.ts +++ b/tests/features/generates_type_guards_for_simple_interface.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for simple interface', @@ -26,4 +26,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_type_properties_with_numerical_names.ts b/tests/features/generates_type_guards_for_type_properties_with_numerical_names.test.ts similarity index 92% rename from tests/features/generates_type_guards_for_type_properties_with_numerical_names.ts rename to tests/features/generates_type_guards_for_type_properties_with_numerical_names.test.ts index 71361fe..cd28344 100644 --- a/tests/features/generates_type_guards_for_type_properties_with_numerical_names.ts +++ b/tests/features/generates_type_guards_for_type_properties_with_numerical_names.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for type properties with numerical names', @@ -26,4 +26,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_for_type_property_with_empty_string_as_name.ts b/tests/features/generates_type_guards_for_type_property_with_empty_string_as_name.test.ts similarity index 92% rename from tests/features/generates_type_guards_for_type_property_with_empty_string_as_name.ts rename to tests/features/generates_type_guards_for_type_property_with_empty_string_as_name.test.ts index 7daf672..394ff12 100644 --- a/tests/features/generates_type_guards_for_type_property_with_empty_string_as_name.ts +++ b/tests/features/generates_type_guards_for_type_property_with_empty_string_as_name.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards for type property with empty string as name', @@ -24,4 +24,4 @@ testProcessProject( ) }`, } -) \ No newline at end of file +) diff --git a/tests/features/generates_type_guards_with_a_short_circuit.ts b/tests/features/generates_type_guards_with_a_short_circuit.test.ts similarity index 93% rename from tests/features/generates_type_guards_with_a_short_circuit.ts rename to tests/features/generates_type_guards_with_a_short_circuit.test.ts index 9d0482d..dc781b6 100644 --- a/tests/features/generates_type_guards_with_a_short_circuit.ts +++ b/tests/features/generates_type_guards_with_a_short_circuit.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'generates type guards with a short circuit', @@ -28,4 +28,4 @@ testProcessProject( { options: { shortCircuitCondition: 'DEBUG', debug: false }, } -) \ No newline at end of file +) diff --git a/tests/features/imports_and_uses_generated_type_guard_if_the_type_is_used_in_another_file.ts b/tests/features/imports_and_uses_generated_type_guard_if_the_type_is_used_in_another_file.test.ts similarity index 96% rename from tests/features/imports_and_uses_generated_type_guard_if_the_type_is_used_in_another_file.ts rename to tests/features/imports_and_uses_generated_type_guard_if_the_type_is_used_in_another_file.test.ts index 5c3169e..dae1fd4 100644 --- a/tests/features/imports_and_uses_generated_type_guard_if_the_type_is_used_in_another_file.ts +++ b/tests/features/imports_and_uses_generated_type_guard_if_the_type_is_used_in_another_file.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'imports and uses generated type guard if the type is used in another file', @@ -48,4 +48,4 @@ testProcessProject( } `, } -) \ No newline at end of file +) diff --git a/tests/features/prefixes_key_with_underscore_if_it_goes_unused.ts b/tests/features/prefixes_key_with_underscore_if_it_goes_unused.test.ts similarity index 93% rename from tests/features/prefixes_key_with_underscore_if_it_goes_unused.ts rename to tests/features/prefixes_key_with_underscore_if_it_goes_unused.test.ts index a701b70..3bf9242 100644 --- a/tests/features/prefixes_key_with_underscore_if_it_goes_unused.ts +++ b/tests/features/prefixes_key_with_underscore_if_it_goes_unused.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'prefixes key with underscore if it goes unused', @@ -27,4 +27,4 @@ testProcessProject( } `, } -) \ No newline at end of file +) diff --git a/tests/features/prefixes_value_with_underscore_if_it_goes_unused.ts b/tests/features/prefixes_value_with_underscore_if_it_goes_unused.test.ts similarity index 93% rename from tests/features/prefixes_value_with_underscore_if_it_goes_unused.ts rename to tests/features/prefixes_value_with_underscore_if_it_goes_unused.test.ts index 8ceaea4..bee40f7 100644 --- a/tests/features/prefixes_value_with_underscore_if_it_goes_unused.ts +++ b/tests/features/prefixes_value_with_underscore_if_it_goes_unused.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'prefixes value with underscore if it goes unused', @@ -27,4 +27,4 @@ testProcessProject( } `, } -) \ No newline at end of file +) diff --git a/tests/features/rejects_invalid_guardFileNames.ts b/tests/features/rejects_invalid_guardFileNames.test.ts similarity index 100% rename from tests/features/rejects_invalid_guardFileNames.ts rename to tests/features/rejects_invalid_guardFileNames.test.ts diff --git a/tests/features/removes_correct_guardts_files_when_guardFileName_is_set.ts b/tests/features/removes_correct_guardts_files_when_guardFileName_is_set.test.ts similarity index 86% rename from tests/features/removes_correct_guardts_files_when_guardFileName_is_set.ts rename to tests/features/removes_correct_guardts_files_when_guardFileName_is_set.test.ts index 48fc62b..f1e2796 100644 --- a/tests/features/removes_correct_guardts_files_when_guardFileName_is_set.ts +++ b/tests/features/removes_correct_guardts_files_when_guardFileName_is_set.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'removes correct .guard.ts files when guardFileName is set', @@ -8,4 +8,4 @@ testProcessProject( }, { 'test.guard.ts': null }, { options: { guardFileName: 'foo' } } -) \ No newline at end of file +) diff --git a/tests/features/removes_existing_guardts_files.ts b/tests/features/removes_existing_guardts_files.test.ts similarity index 75% rename from tests/features/removes_existing_guardts_files.ts rename to tests/features/removes_existing_guardts_files.test.ts index 037c102..23c35c9 100644 --- a/tests/features/removes_existing_guardts_files.ts +++ b/tests/features/removes_existing_guardts_files.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'removes existing .guard.ts files', @@ -6,4 +6,4 @@ testProcessProject( 'test.guard.ts': `/* WARNING: Do not manually change this file. */ alert("hello")`, }, {} -) \ No newline at end of file +) diff --git a/tests/features/show_debug_info.ts b/tests/features/show_debug_info.test.ts similarity index 97% rename from tests/features/show_debug_info.ts rename to tests/features/show_debug_info.test.ts index 3e09a26..8a8ade4 100644 --- a/tests/features/show_debug_info.ts +++ b/tests/features/show_debug_info.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'show debug info', @@ -69,4 +69,4 @@ testProcessProject( debug: true, }, } -) \ No newline at end of file +) diff --git a/tests/features/skips_checking_any_type_in_array.ts b/tests/features/skips_checking_any_type_in_array.test.ts similarity index 88% rename from tests/features/skips_checking_any_type_in_array.ts rename to tests/features/skips_checking_any_type_in_array.test.ts index a449c4f..a2dbc07 100644 --- a/tests/features/skips_checking_any_type_in_array.ts +++ b/tests/features/skips_checking_any_type_in_array.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'skips checking any type in array', @@ -18,4 +18,4 @@ testProcessProject( }`, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/features/type_that_is_an_alias_to_an_interface_has_a_different_typeguard_name.ts b/tests/features/type_that_is_an_alias_to_an_interface_has_a_different_typeguard_name.test.ts similarity index 96% rename from tests/features/type_that_is_an_alias_to_an_interface_has_a_different_typeguard_name.ts rename to tests/features/type_that_is_an_alias_to_an_interface_has_a_different_typeguard_name.test.ts index f68b714..bd595cb 100644 --- a/tests/features/type_that_is_an_alias_to_an_interface_has_a_different_typeguard_name.ts +++ b/tests/features/type_that_is_an_alias_to_an_interface_has_a_different_typeguard_name.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'type that is an alias to an interface has a different typeguard name', @@ -39,4 +39,4 @@ testProcessProject( `, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/features/uses_correct_import_file_name_if_guard_file_is_renamed.ts b/tests/features/uses_correct_import_file_name_if_guard_file_is_renamed.test.ts similarity index 93% rename from tests/features/uses_correct_import_file_name_if_guard_file_is_renamed.ts rename to tests/features/uses_correct_import_file_name_if_guard_file_is_renamed.test.ts index a173027..7aaff29 100644 --- a/tests/features/uses_correct_import_file_name_if_guard_file_is_renamed.ts +++ b/tests/features/uses_correct_import_file_name_if_guard_file_is_renamed.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'uses correct import file name if guard file is renamed', @@ -33,4 +33,4 @@ testProcessProject( }, skip: true, } -) \ No newline at end of file +) diff --git a/tests/features/works_for_any_type.ts b/tests/features/works_for_any_type.test.ts similarity index 87% rename from tests/features/works_for_any_type.ts rename to tests/features/works_for_any_type.test.ts index dfb54cb..a835c1a 100644 --- a/tests/features/works_for_any_type.ts +++ b/tests/features/works_for_any_type.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'works for any type', @@ -18,4 +18,4 @@ testProcessProject( }`, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/features/works_for_unknown_type.ts b/tests/features/works_for_unknown_type.test.ts similarity index 87% rename from tests/features/works_for_unknown_type.ts rename to tests/features/works_for_unknown_type.test.ts index c2b4a39..7616501 100644 --- a/tests/features/works_for_unknown_type.ts +++ b/tests/features/works_for_unknown_type.test.ts @@ -1,4 +1,4 @@ -import {testProcessProject} from '../generate'; +import { testProcessProject } from '../generate' testProcessProject( 'works for unknown type', @@ -18,4 +18,4 @@ testProcessProject( }`, }, { options: { exportAll: true } } -) \ No newline at end of file +) diff --git a/tests/import.ts b/tests/import.test.ts similarity index 100% rename from tests/import.ts rename to tests/import.test.ts diff --git a/tsconfig.json b/tsconfig.json index 9d80ef1..b96c905 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,8 @@ // "outFile": "./", /* Concatenate and emit output to single file. */ "outDir": "./lib" /* Redirect output structure to the directory. */, "rootDirs": [ - "./src"] /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, + "./src" + ] /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, // "composite": true, /* Enable project compilation */ // "removeComments": true, /* Do not emit comments to output. */ // "noEmit": true, /* Do not emit outputs. */