Skip to content

Commit

Permalink
refactor: move resolving function to the import manager
Browse files Browse the repository at this point in the history
  • Loading branch information
svenliebig committed Oct 4, 2022
1 parent abe82c5 commit ec9ac81
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 85 deletions.
80 changes: 0 additions & 80 deletions src/models/Import.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createSourceFile, isEnumDeclaration, isImportDeclaration, isLiteralType
import { FileManager } from "./utils/FileManager"
import { ArrayType } from "./models/ArrayType"
import { ArrayTypeDeclaration } from "./models/ArrayTypeDeclaration"
import { Import } from "./models/Import"
import { Import } from "./utils/imports/model"
import { IntersectionType } from "./models/IntersectionType"
import { IntersectionTypeDeclaration } from "./models/IntersectionTypeDeclaration"
import { StringType } from "./models/StringType"
Expand Down Expand Up @@ -142,7 +142,7 @@ export class Parser {
// - remove import
// - parse
private resolveImport(imported: Import) {
const path = imported.resolve()
const path = this.importManager.resolve(imported)
this.parseFile(path)
this.importManager.remove(imported)
}
Expand Down
17 changes: 17 additions & 0 deletions src/utils/imports/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Import } from "./model"

export class UnresolvedImportError extends Error {
constructor(imp: Import) {
super()
this.message = this.createMessage(imp)
}

private createMessage(imp: Import): string {
return [
`Could not resolve ${imp.toString()} from "${imp.from}".`,
"",
"It is possible to suppress this error when the 'breakOnUnresolvedImport' options is set to 'false'.",
"The type will resolve to unknown then.",
].join("\n")
}
}
2 changes: 1 addition & 1 deletion src/utils/imports/factory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ImportDeclaration, isImportClause, isImportSpecifier, isNamedImports, isStringLiteralLike } from "typescript"
import { Import } from "../../models/Import"
import { Import } from "./model"

/**
* For translating `typescript` AST nodes into our own model type.
Expand Down
41 changes: 40 additions & 1 deletion src/utils/imports/manager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Import } from "../../models/Import"
import { existsSync } from "fs"
import { resolve } from "path"
import { Import } from "./model"
import { L } from "../logger"
import { UnresolvedImportError } from "./errors"

export class ImportManager {
private imports: Array<Import> = []
Expand All @@ -17,4 +21,39 @@ export class ImportManager {
public remove(i: Import) {
this.imports.splice(this.imports.indexOf(i), 1)
}

public resolve(i: Import) {
const lp = [`<ImportManager.resolve>`, i.toString()]
L.d(...lp)

if (isRelativePath(i.from)) {
const pathToFile = resolve(i.sourceDir, i.from)

const tsPath = `${pathToFile}.ts`
const tsxPath = `${pathToFile}.tsx`

L.d(...lp, `trying if exists: ${tsPath}`)

if (existsSync(tsPath)) {
L.d(...lp, `"${tsPath}" path exists`)
return tsPath
}

if (existsSync(tsxPath)) {
L.d(...lp, `"${tsPath}" path exists`)
return tsxPath
}

throw new UnresolvedImportError(i)
} else {
// this is a library
// TODO node_modules
// TODO @types
throw new UnresolvedImportError(i)
}
}
}

function isRelativePath(s: string) {
return s.startsWith("../") || s.startsWith("./")
}
44 changes: 44 additions & 0 deletions src/utils/imports/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { parse } from "path"

export class Import {
private _sourceDir: string | null = null

constructor(
/** the path of the file that contains the import declaration. */
public source: string,
/** the relative path to the target file of the import. */
public from: string,
/** the named exports (`import { named } from "./from"`). */
private named: Array<string>,
/** the default exports (`import default from "./from"`). */
private default_: string | null
) {}

public get sourceDir(): string {
if (!this._sourceDir) {
this._sourceDir = parse(this.source).dir
}
return this._sourceDir
}

/**
* Checks if the {@link Import} contains a specific identifier.
*
* For example: `import Jon, { Doe } from "./helloworld"`
*
* Would result in:
*
* ```ts
* containsIdentifier("Jon") // true
* containsIdentifier("Doe") // true
* containsIdentifier("helloworld") // false
* ```
*/
public containsIdentifier(name: string) {
return this.default_ === name || this.named.includes(name)
}

public toString() {
return `import ${this.default_ ? `${this.default_} ` : ""}${this.named.length > 0 ? `{ ${this.named.join(", ")} }` : ""} from "${this.from}"`
}
}
2 changes: 1 addition & 1 deletion tests/configuration.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import test from "ava"
import { resolve } from "path"
import { UnresolvedImportError } from "../src/models/Import"
import { UnknownType } from "../src/models/UnknownType"
import { Parser } from "../src/parser"
import { UnresolvedImportError } from "../src/utils/imports/errors"

test("breakOnUnresolvedImports: true", (t) => {
const parser = new Parser(resolve(__dirname, "fixtures", "configurationTestTypes.ts"), { breakOnUnresolvedImports: true })
Expand Down

0 comments on commit ec9ac81

Please sign in to comment.