Skip to content

Commit

Permalink
feat: add a file manager, that tracks currently only on enums and in …
Browse files Browse the repository at this point in the history
…which file these are stored
  • Loading branch information
svenliebig committed Sep 29, 2022
1 parent 58338c8 commit cb455f9
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 26 deletions.
62 changes: 36 additions & 26 deletions src/parser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { readFileSync } from "fs"
import { createSourceFile, isEnumDeclaration, isImportDeclaration, isLiteralTypeNode, isTypeAliasDeclaration, ScriptTarget } from "typescript"
import { FileManager } from "./utils/FileManager"
import { ArrayType } from "./models/ArrayType"
import { ArrayTypeDeclaration } from "./models/ArrayTypeDeclaration"
import { Import } from "./models/Import"
Expand Down Expand Up @@ -67,6 +68,8 @@ export class Parser {
private declarations: Array<TypeDeclaration> = []
private config: Required<ParserConfig>

private fileManager = new FileManager()

constructor(path: string, config: ParserConfig = {}) {
this.config = {
...DEFAULT_CONFIG,
Expand All @@ -77,12 +80,13 @@ export class Parser {
}

private parseFile(path: string) {
const lp = [`<parseFile>`, path]
const content = readFileSync(path, "utf-8")
const file = createSourceFile("e", content, ScriptTarget.ESNext)
L.d(`<parseFile>`, `statements.length: ${file.statements.length}`)
L.d(...lp, `statements.length: ${file.statements.length}`)

file.statements.forEach((statement) => {
L.d(`<parseFile>`, `statement: ${statement.kind}`)
L.d(...lp, `statement: ${statement.kind}`)
if (isImportDeclaration(statement)) {
this.imports.push(importFactory(statement, path))
}
Expand All @@ -93,35 +97,30 @@ export class Parser {
if (isEnumDeclaration(statement)) {
const declaration = DeclarationFactory.createEnumDeclaration(statement)
// TODO refactor probably...
L.d(`<parserFile>`, "push declaration", declaration.toString())
L.d(...lp, "enum", "push declaration", declaration.toString())
this.fileManager.addTypeDeclarationToFile(path, declaration)
return this.declarations.push(declaration)
}

if (isTypeAliasDeclaration(statement)) {
const declaration = DeclarationFactory.createTypeDeclaration(statement)
// TODO refactor probably...
L.d(`<parserFile>`, "push declaration", declaration.toString())
L.d(...lp, "typeAliasDeclaration", "push declaration", declaration.toString())
return this.declarations.push(declaration)
}
})
}

public getDeclaration(name: string) {
return this.declarations.find((type) => type.identifier === name)
public getDeclarations(): Array<TypeDeclaration> {
return this.declarations
}

private getImport(name: string) {
return this.imports.find((imported) => imported.containsIdentifier(name))
public getSourcePathOf(declaration: TypeDeclaration) {
return this.fileManager.getFilePathOf(declaration)
}

// TODO split this up into:
// - resolve import return string path
// - remove import
// - parse
private resolveImport(imported: Import) {
const path = imported.resolve()
this.parseFile(path)
this.imports.splice(this.imports.indexOf(imported), 1)
public getDeclaration(name: string) {
return this.declarations.find((type) => type.identifier === name)
}

/**
Expand All @@ -137,31 +136,46 @@ export class Parser {
return false
}

private getImport(name: string) {
return this.imports.find((imported) => imported.containsIdentifier(name))
}

// TODO split this up into:
// - resolve import return string path
// - remove import
// - parse
private resolveImport(imported: Import) {
const path = imported.resolve()
this.parseFile(path)
this.imports.splice(this.imports.indexOf(imported), 1)
}

private isTypeResolved(type: Type): type is Type {
L.d(`<isTypeResolved>`, type.toString())
const lp = [`<isTypeResolved>`, type.toString()]
L.d(...lp)

if (type instanceof TypeReference && !type.isPrimitive() && !this.config.doNotResolve.includes(type.identifier)) {
L.d(`<isTypeResolved>`, "it's a type reference and not primitive, return false")
L.d(...lp, "it's a type reference and not primitive, return false")
return false
}

if (type instanceof TypeLiteral) {
L.d(`<isTypeResolved>`, "it's a type literal, checking all properties")
L.d(...lp, "it's a type literal, checking all properties")
return !Array.from(type.properties.values()).some((property) => !this.isTypeResolved(property))
}

if (type instanceof UnionType) {
L.d(`<isTypeResolved>`, "it's a union type, checking all types")
L.d(...lp, "it's a union type, checking all types")
return !type.types.some((type) => !this.isTypeResolved(type))
}

if (type instanceof IntersectionType) {
L.d(`<isTypeResolved>`, "it's an intersection type, checking all types")
L.d(...lp, "it's an intersection type, checking all types")
return !type.types.some((type) => !this.isTypeResolved(type))
}

if (type instanceof ArrayType) {
L.d(`<isTypeResolved>`, "it's an array type, checking type of the Array")
L.d(...lp, "it's an array type, checking type of the Array")
return this.isTypeResolved(type.arrayType)
}

Expand All @@ -171,10 +185,6 @@ export class Parser {
return true
}

public getDeclarations(): Array<TypeDeclaration> {
return this.declarations
}

public resolve(name: string) {
L.d(`<resolve>`, name)

Expand Down
36 changes: 36 additions & 0 deletions src/utils/FileManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { normalize } from "path"
import { TypeDeclaration } from "../models/TypeDeclaration"
import { L } from "./logger"

export class FileManager {
private files: Map<string, Array<string>> = new Map()

public addTypeDeclarationToFile(file: string, declaration: TypeDeclaration) {
const lp = [`<addTypeDeclarationToFile>`, file, declaration.identifier]
L.d(...lp)
const path = normalize(file)
if (!this.files.has(path)) {
L.d(...lp, "!hasPath", "we add an empty array on that entry")
this.files.set(path, [])
}

const declarations = this.files.get(path)! // we know this because of the previous !has
if (!declarations.includes(declaration.identifier)) {
L.d(...lp, "the identifier is not included", "added the identifier to the array")
declarations?.push(declaration.identifier)
} else {
L.d(...lp, "the identifier is already")
}
}

public getFilePathOf(declaration: TypeDeclaration) {
for (const entry of this.files) {
const declarations = entry[1]
if (declarations.includes(declaration.identifier)) {
return entry[0]
}
}

return null
}
}
24 changes: 24 additions & 0 deletions tests/utils/fileManager.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import test from "ava"
import { resolve } from "path"
import { tmpdir } from "os"
import { FileManager } from "../../src/utils/FileManager"
import { StringTypeDeclaration } from "../../src/models/StringTypeDeclaration"

const dir = tmpdir()

test("fileManager should add a declaration to a file a path", (t) => {
const manager = new FileManager()
const declaration = new StringTypeDeclaration({ default: false, exported: true, identifier: "Hello" })
manager.addTypeDeclarationToFile(resolve(dir, "a.ts"), declaration)
t.is(manager.getFilePathOf(declaration), resolve(dir, "a.ts"))
})

test("fileManager should add two declarations to the same file", (t) => {
const manager = new FileManager()
const declaration1 = new StringTypeDeclaration({ default: false, exported: true, identifier: "Hello1" })
const declaration2 = new StringTypeDeclaration({ default: false, exported: true, identifier: "Hello2" })
manager.addTypeDeclarationToFile(resolve(dir, "a.ts"), declaration1)
manager.addTypeDeclarationToFile(resolve(dir, "a.ts"), declaration2)
t.is(manager.getFilePathOf(declaration1), resolve(dir, "a.ts"))
t.is(manager.getFilePathOf(declaration2), resolve(dir, "a.ts"))
})

0 comments on commit cb455f9

Please sign in to comment.