feat: tests

This commit is contained in:
2023-04-21 12:08:35 +02:00
parent 8cb9285462
commit d8c79256c9
140 changed files with 2100 additions and 2693 deletions

View File

@@ -10,34 +10,33 @@
"types": "./lib/index.d.ts",
"scripts": {
"build": "tsup --dts",
"format": "prettier .",
"format:fix": "prettier --write .",
"format": "prettier . --ignore-path ../../.gitignore",
"format:fix": "prettier --write . --ignore-path ../../.gitignore",
"lint": "eslint --ext .ts src/",
"lint:fix": "eslint --fix --ext .ts src/",
"test": "nyc mocha 'test/**/*.spec.ts'"
"test": "c8 mocha"
},
"dependencies": {
"@openstapps/collection-utils": "workspace:*",
"@openstapps/logger": "workspace:*",
"glob": "10.2.1",
"typescript": "4.8.4"
},
"devDependencies": {
"@openstapps/eslint-config": "workspace:*",
"@openstapps/nyc-config": "workspace:*",
"@openstapps/prettier-config": "workspace:*",
"@openstapps/tsconfig": "workspace:*",
"@testdeck/mocha": "0.3.3",
"@types/chai": "4.3.4",
"@types/fs-extra": "9.0.13",
"@types/mocha": "10.0.1",
"@types/node": "18.15.3",
"c8": "7.13.0",
"chai": "4.3.7",
"mocha": "10.2.0",
"nock": "13.3.0",
"ts-node": "10.9.1",
"tsup": "6.7.0"
},
"tsup": {
"entry": [
"src/app.ts",
"src/index.ts"
],
"sourcemap": true,
@@ -54,8 +53,5 @@
"eslintIgnore": [
"resources",
"openapi"
],
"nyc": {
"extends": "@openstapps/nyc-config"
}
]
}

View File

@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import * as ts from 'typescript';
import ts from 'typescript';
import {cleanupEmpty} from './util.js';
import {LightweightComment} from './types/lightweight-comment.js';
@@ -33,7 +33,7 @@ export function extractComment(node: ts.Node): LightweightComment | undefined {
? undefined
: cleanupEmpty({
shortSummary: comment?.[0],
description: comment?.[comment.length - 1],
description: comment?.slice(1).join('\n\n'),
tags: jsDocument?.tags?.map(tag =>
cleanupEmpty({
name: tag.tagName?.escapedText ?? 'UNRESOLVED_NAME',

View File

@@ -14,7 +14,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import ts from 'typescript';
import {cleanupEmpty, mapNotNil, rejectNil, expandPathToFilesSync} from './util.js';
import {cleanupEmpty, expandPathToFilesSync, mapNotNil, rejectNil} from './util.js';
import {
extractComment,
filterChildrenTo,
@@ -77,7 +77,7 @@ class LightweightDefinitionBuilder {
constructor(sourcePath: string | string[], readonly includeComments: boolean) {
const rootNames = Array.isArray(sourcePath)
? sourcePath
: expandPathToFilesSync(path.resolve(sourcePath), file => file.endsWith('ts'));
: expandPathToFilesSync(path.resolve(sourcePath), it => it.endsWith('.ts'));
this.program = ts.createProgram({
rootNames: rootNames,
@@ -121,7 +121,7 @@ class LightweightDefinitionBuilder {
classLike: ts.ClassDeclaration | ts.InterfaceDeclaration,
): LightweightClassDefinition {
const heritages = mapValues(
groupBy([...classLike.heritageClauses!], it => it.token.toString()),
groupBy([...(classLike.heritageClauses || [])], it => it.token.toString()),
heritages => heritages.flatMap(it => it.types),
);
@@ -162,23 +162,25 @@ class LightweightDefinitionBuilder {
collectProperties(
members: ts.NodeArray<ts.ClassElement | ts.TypeElement>,
): Record<string, LightweightProperty> {
return keyBy(
filterNodeTo(members as ts.NodeArray<ts.ClassElement | ts.TypeElement>, isProperty).map(property =>
cleanupEmpty({
comment: this.includeComments ? extractComment(property) : undefined,
name: resolvePropertyName(property.name) ?? property.getText(),
type: this.lightweightTypeAtNode(property),
properties: this.collectProperties((property.type as ts.TypeLiteralNode)?.members),
optional: ts.isPropertyDeclaration(property)
? property.questionToken === undefined
? undefined
: true
: undefined,
}),
),
it => it.name,
);
): Record<string, LightweightProperty> | undefined {
return members
? keyBy(
filterNodeTo(members as ts.NodeArray<ts.ClassElement | ts.TypeElement>, isProperty).map(property =>
cleanupEmpty({
comment: this.includeComments ? extractComment(property) : undefined,
name: resolvePropertyName(property.name) ?? property.getText(),
type: this.lightweightTypeAtNode(property),
properties: this.collectProperties((property.type as ts.TypeLiteralNode)?.members),
optional: ts.isPropertyDeclaration(property)
? property.questionToken === undefined
? undefined
: true
: undefined,
}),
),
it => it.name,
)
: undefined;
}
private lightweightTypeAtNode(node: ts.Node): LightweightType {

View File

@@ -12,14 +12,14 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
export * from './easy-ast.js'
export * from './ast-util.js'
export * from './easy-ast.js';
export * from './ast-util.js';
export * from './types/lightweight-alias-definition.js'
export * from './types/lightweight-class-definition.js'
export * from './types/lightweight-comment.js'
export * from './types/lightweight-definition.js'
export * from './types/lightweight-definition-kind.js'
export * from './types/lightweight-project.js'
export * from './types/lightweight-property.js'
export * from './types/lightweight-type.js'
export * from './types/lightweight-alias-definition.js';
export * from './types/lightweight-class-definition.js';
export * from './types/lightweight-comment.js';
export * from './types/lightweight-definition.js';
export * from './types/lightweight-definition-kind.js';
export * from './types/lightweight-project.js';
export * from './types/lightweight-property.js';
export * from './types/lightweight-type.js';

View File

@@ -12,15 +12,36 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import path from "path";
import {readdirSync, statSync} from "fs";
import {readdirSync, statSync} from 'fs';
import path from 'path';
/**
* Expand a path to a list of all files deeply contained in it
*/
export function expandPathToFilesSync(sourcePath: string, accept: (fileName: string) => boolean): string[] {
const fullPath = path.resolve(sourcePath);
const directory = statSync(fullPath);
return directory.isDirectory()
? readdirSync(fullPath).flatMap(fragment =>
expandPathToFilesSync(path.resolve(sourcePath, fragment), accept),
)
: [fullPath].filter(accept);
}
/**
* Take a Windows path and make a Unix path out of it
*/
export function toUnixPath(pathString: string): string {
return pathString.replaceAll(path.sep, path.posix.sep);
}
/**
* Filters only defined elements
*/
export function rejectNil<T>(array: Array<T | undefined | null>): T[] {
// eslint-disable-next-line unicorn/no-null
return array.filter(it => it == null) as T[];
return array.filter(it => it != null) as T[];
}
/**
@@ -45,17 +66,3 @@ export function cleanupEmpty<T extends object>(object: T): T {
}
return out;
}
/**
* Expand a path to a list of all files deeply contained in it
*/
export function expandPathToFilesSync(sourcePath: string, accept: (fileName: string) => boolean): string[] {
const fullPath = path.resolve(sourcePath);
const directory = statSync(fullPath);
return directory.isDirectory()
? readdirSync(fullPath).flatMap(fragment =>
expandPathToFilesSync(path.resolve(sourcePath, fragment), accept),
)
: [fullPath].filter(accept);
}

View File

@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {LightweightFile} from '../../src/easy-ast/types/lightweight-project.js';
import {LightweightFile} from '../src/index.js';
export interface EasyAstSpecType {
testName: string;

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2021 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {lightweightProjectFromPath} from '../src/index.js';
import {expect} from 'chai';
import {expandPathToFilesSync, toUnixPath} from '../src/util.js';
import type {EasyAstSpecType} from './easy-ast-spec-type.js';
const projectPath = './test/project';
const tests = await Promise.all(
expandPathToFilesSync(projectPath, file => file.endsWith('ast-test.ts')).map(async it => ({
path: toUnixPath(it),
config: await import(`file://${it}`).then(it => it.testConfig as EasyAstSpecType),
})),
);
describe('Easy AST', async function () {
it('should build the project', function () {
const project = lightweightProjectFromPath(projectPath, true);
expect(Object.keys(project).length).to.equal(tests.length);
});
const project = lightweightProjectFromPath(projectPath, true);
for (const {path, config} of tests) {
it(config.testName, function () {
const projectAtPath = project[path];
expect(projectAtPath).not.to.be.undefined;
for (const key in projectAtPath) {
if (key.startsWith('$')) delete projectAtPath[key];
}
expect(projectAtPath).to.be.deep.equal(config.expected);
});
}
});

View File

@@ -1,35 +0,0 @@
/*
* Copyright (C) 2021 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {expandPathToFilesSync, toUnixPath} from '../src/util.js';
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {lightweightProjectFromPath} from '../src/easy-ast.js';
import {expect} from 'chai';
describe('Easy AST', async () => {
const project = lightweightProjectFromPath('./test/easy-ast', true);
for (const file of expandPathToFilesSync('./test/easy-ast', file => file.endsWith('ast-test.ts'))) {
try {
const test = (await import(file))['testConfig'] as EasyAstSpecType;
it(test.testName, () => {
expect(omitBy(project[toUnixPath(file)], (_value, key) => key.startsWith('$'))).to.be.deep.equal(
test.expected,
);
});
} catch (error) {
console.error(error);
}
}
});

View File

@@ -13,11 +13,13 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/index.js';
// @ts-expect-error unused type
type TestTypeAlias = number | string;
// @ts-expect-error unused type
enum TestEnum {
Foo,
Bar,

View File

@@ -13,14 +13,18 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/index.js';
interface Random {}
// @ts-expect-error unused type
type TestArrayGeneric = Array<string>;
// @ts-expect-error unused type
type TestArrayLiteral = number[];
// @ts-expect-error unused type
type TestArrayReferenceGeneric = Array<Random>;
// @ts-expect-error unused type
type TestArrayReferenceLiteral = Random[];
export const testConfig: EasyAstSpecType = {

View File

@@ -13,13 +13,15 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/index.js';
// @ts-expect-error unused type
interface TestInterface {
foo: number;
}
// @ts-expect-error unused type
class TestClass {
bar: string = 'test';
}

View File

@@ -13,8 +13,8 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/index.js';
/**
* Class comment
@@ -25,6 +25,7 @@ import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-de
*
* @classTag classParameter1 classParameter2
*/
// @ts-expect-error unused type
interface TestInterface {
/**
* Property comment
@@ -47,6 +48,7 @@ interface TestInterface {
*
* @classTag classParameter1 classParameter2
*/
// @ts-expect-error unused type
class TestClass {
/**
* Property comment
@@ -69,6 +71,7 @@ class TestClass {
*
* @enumTag enumParameter1
*/
// @ts-expect-error unused type
enum TestAlias {}
export const testConfig: EasyAstSpecType = {

View File

@@ -13,13 +13,14 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/index.js';
interface Test1<T = number> {
foo: T;
}
// @ts-expect-error unused type
interface Test2 {
bar: Test1;
}

View File

@@ -13,14 +13,16 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/index.js';
// @ts-expect-error unused type
enum TestAuto {
Foo,
Bar,
}
// @ts-expect-error unused type
enum TestSpecified {
YES = 'yes',
NO = 'no',

View File

@@ -13,11 +13,12 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/index.js';
interface $Random {}
// @ts-expect-error unused type
interface Generics {
baz: Foo<number, $Random>;
}

View File

@@ -13,15 +13,17 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/index.js';
interface $Random {}
// @ts-expect-error unused
interface IndexSignatureObject {
[key: string]: $Random;
}
// @ts-expect-error unused
interface IndexSignaturePrimitive {
[key: string]: number;
}

View File

@@ -13,8 +13,8 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/index.js';
interface $BaseInterface<T> {
foo: T;
@@ -26,6 +26,7 @@ interface $BaseInterface2 {
class $BaseClass {}
// @ts-expect-error unused
class InheritingClass extends $BaseClass implements $BaseInterface<number>, $BaseInterface2 {
bar: string = '';

View File

@@ -13,9 +13,10 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/index.js';
// @ts-expect-error unused
interface NestedObject {
nested: {
deeplyNested: {

View File

@@ -13,9 +13,10 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/index.js';
// @ts-expect-error unused
interface Test {
number_type: number;
string_type: string;

View File

@@ -13,9 +13,10 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {EasyAstSpecType} from './easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
import {LightweightDefinitionKind} from '../../src/index.js';
// @ts-expect-error unused
interface Foo<T extends Bar<string>> {
bar: T;
}