Skip to content

Feat refactor targetting #186

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 80 additions & 62 deletions libraries/analysis-javascript/lib/target/Target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,85 +15,103 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
SubTarget as CoreSubTarget,
Target as CoreTarget,
TargetType,
} from "@syntest/analysis";
import { SubTarget as CoreSubTarget,
Target as CoreTarget, TargetType } from "@syntest/analysis";

import { VisibilityType } from "./VisibilityType";

export interface Target extends CoreTarget {
export class TargetGraph implements CoreTarget {
path: string;
name: string;
subTargets: SubTarget[];
}
subTargets: Target[]; // deprecated
targetMap: Map<string, Target>;
childTargetMap: Map<string, string[]>
parentTargetMap: Map<string, string>

constructor() {
this.targetMap = new Map()
this.childTargetMap = new Map()
this.parentTargetMap = new Map()
}

// TODO check for cycles

hasTarget(targetId: string) {
return this.targetMap.has(targetId)
}

addTarget(target: Target, parent?: Target) {
if (this.targetMap.has(target.id)) {
throw new Error('Each target can only exists once!')
}
this.targetMap.set(target.id, target)
this.childTargetMap.set(target.id, [])
if (parent) {
if (!this.targetMap.has(parent.id)) {
throw new Error('parent does not exist! Targets should be added in order')
}
this.parentTargetMap.set(target.id, parent.id)
this.childTargetMap.get(parent.id).push(target.id)
}
}

getParentId(target: Target | string): undefined | string {
return typeof target === 'string' ? this.parentTargetMap.get(target) : this.parentTargetMap.get(target.id)
}

getChildrenIds(target: Target | string): undefined | string[] {
return typeof target === 'string' ? this.childTargetMap.get(target) : this.childTargetMap.get(target.id)
}

getParent(target: Target | string): undefined | Target {
const parentId = typeof target === 'string' ? this.parentTargetMap.get(target) : this.parentTargetMap.get(target.id)
return parentId ? this.targetMap.get(parentId) : undefined
}

getChildren(target: Target | string): undefined | Target[] {
const childrenIds = typeof target === 'string' ? this.childTargetMap.get(target) : this.childTargetMap.get(target.id)
return childrenIds ? childrenIds.map((id) => this.targetMap.get(id)) : undefined
}
};

export interface SubTarget extends CoreSubTarget {
type: TargetType;
id: string;
}
export type Target = RootTarget | CoverageTarget
export type RootTarget = ClassTarget | ObjectTarget | FunctionTarget
export type CoverageTarget = LineTarget | BranchTarget | PathTarget

export interface NamedSubTarget extends SubTarget {
name: string;
export type BaseTarget = CoreSubTarget & {
id: string;
typeId: string;
}

export type Exportable = {
exported: boolean;
// maybe scope?
renamedTo?: string;
module?: boolean;
default?: boolean;
exportId: string;
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isExported(target: any): target is Exportable {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
return "exported" in target && target.exported === true;
}

export interface Callable {
isAsync: boolean;
}

export interface FunctionTarget extends NamedSubTarget, Exportable, Callable {
type: TargetType.FUNCTION;
}

export interface ClassTarget extends NamedSubTarget, Exportable {
export type ClassTarget = BaseTarget & {
type: TargetType.CLASS;
}
};

export interface MethodTarget extends NamedSubTarget, Callable {
type: TargetType.METHOD;
classId: string;
export type ObjectTarget = BaseTarget & {
type: TargetType.OBJECT;
};

export type FunctionTarget = BaseTarget & {
type: TargetType.FUNCTION;
isAsync: boolean;
isStatic: boolean;
visibility: VisibilityType;

methodType: "constructor" | "method" | "get" | "set";
isStatic: boolean;
}

export interface ObjectTarget extends NamedSubTarget, Exportable {
type: TargetType.OBJECT;
}

export interface ObjectFunctionTarget extends NamedSubTarget, Callable {
type: TargetType.OBJECT_FUNCTION;
objectId: string;
}
};

export interface PathTarget extends SubTarget {
type: TargetType.PATH;
ids: string[];
export type LineTarget = {
id: string
type: TargetType.LINE
}

export interface BranchTarget extends SubTarget {
type: TargetType.BRANCH;
export type BranchTarget = {
id: string
type: TargetType.BRANCH

}

export interface LineTarget extends SubTarget {
type: TargetType.LINE;
line: number;
}
export type PathTarget = {
id: string
type: TargetType.PATH
}
19 changes: 2 additions & 17 deletions libraries/analysis-javascript/lib/target/TargetFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,17 @@
* limitations under the License.
*/

import * as path from "node:path";

import { traverse } from "@babel/core";
import * as t from "@babel/types";
import { TargetFactory as CoreTargetFactory } from "@syntest/analysis";

import { Factory } from "../Factory";

import { ExportVisitor } from "./export/ExportVisitor";
import { Target } from "./Target";
import { TargetVisitor } from "./TargetVisitor";

/**
* TargetFactory for Javascript.
*
* @author Dimitri Stallenberg
*/
export class TargetFactory
extends Factory
Expand All @@ -44,23 +39,13 @@ export class TargetFactory
* @param AST The AST of the target
*/
extract(filePath: string, AST: t.Node): Target {
// bit sad that we have to do this twice, but we need to know the exports
const exportVisitor = new ExportVisitor(filePath, this.syntaxForgiving);

traverse(AST, exportVisitor);

const exports = exportVisitor.exports;
const visitor = new TargetVisitor(filePath, this.syntaxForgiving, exports);
const visitor = new TargetVisitor(filePath, this.syntaxForgiving);

traverse(AST, visitor);

// we should check wether every export is actually used
// TODO

return {
path: filePath,
name: path.basename(filePath),
subTargets: visitor.subTargets,
};
return visitor._getTargetGraph()
}
}
Loading