Skip to content

Commit 50aab94

Browse files
committed
feat: 🎸 workspace api refactoring, update project api
1 parent d4348f2 commit 50aab94

File tree

10 files changed

+195
-85
lines changed

10 files changed

+195
-85
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
export * from './workspace-connect.dto';
2+
export * from './update-project.dto';
3+
export * from './project.dto';
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Project } from '@angular-cli-gui/shared/data';
2+
import { JsonValue } from '@angular-devkit/core';
3+
import { ProjectDefinition } from '@angular-devkit/core/src/workspace';
4+
5+
export class ProjectDto implements Project {
6+
root: string;
7+
prefix?: string;
8+
sourceRoot?: string;
9+
extensions: Record<string, JsonValue | undefined>;
10+
11+
constructor(projectDefinition: ProjectDefinition) {
12+
this.root = projectDefinition.root;
13+
this.prefix = projectDefinition.prefix;
14+
this.sourceRoot = projectDefinition.sourceRoot;
15+
this.extensions = projectDefinition.extensions;
16+
}
17+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { IUpdateProjectDto } from '@angular-cli-gui/shared/data';
2+
import { JsonValue } from '@angular-devkit/core';
3+
import { IsOptional, IsString } from 'class-validator';
4+
5+
export class UpdateProjectDto implements IUpdateProjectDto {
6+
@IsString()
7+
@IsOptional()
8+
root?: string;
9+
10+
@IsString()
11+
@IsOptional()
12+
prefix?: string;
13+
14+
@IsString()
15+
@IsOptional()
16+
sourceRoot?: string;
17+
18+
extensions?: Record<string, JsonValue | undefined>;
19+
}

‎apps/cli-daemon/src/app/workspace/workspace.controller.ts‎

Lines changed: 25 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
import {
2-
ProjectDefinition,
3-
TargetDefinition,
4-
} from '@angular-devkit/core/src/workspace';
1+
import { TargetDefinition } from '@angular-devkit/core/src/workspace';
52
import {
63
Body,
74
Controller,
85
Get,
96
InternalServerErrorException,
107
Logger,
11-
NotFoundException,
128
Param,
9+
Patch,
1310
Post,
1411
} from '@nestjs/common';
1512

@@ -18,7 +15,7 @@ import { GeneratorsService } from '../generators/generators.service';
1815
import { CREATE_WORKSPACE_COMMAND } from '../ng-commands';
1916
import { SessionService } from '../session/session.service';
2017

21-
import { WorkspaceConnectDto } from './dto';
18+
import { ProjectDto, UpdateProjectDto, WorkspaceConnectDto } from './dto';
2219
import { WorkspaceCreateDto } from './dto/workspace-create.dto';
2320
import { WorkspaceService } from './workspace.service';
2421

@@ -34,9 +31,7 @@ export class WorkspaceController {
3431

3532
@Post('connect')
3633
async connect(@Body() body: WorkspaceConnectDto): Promise<void> {
37-
const path = body.path;
38-
await this.workspaceService.readWorkspace(path);
39-
this.sessionService.setCwd(path);
34+
await this.workspaceService.connect(body.path);
4035
}
4136

4237
@Post('create')
@@ -60,68 +55,45 @@ export class WorkspaceController {
6055
return { path: this.sessionService.cwd };
6156
}
6257

63-
@Get()
58+
@Get('project-names')
6459
getWorkspaceProjectNames(): Promise<string[]> {
6560
return this.workspaceService.readWorkspaceProjectNames();
6661
}
6762

68-
@Get(':projectName')
63+
@Get('project/:projectName')
6964
async getProject(
7065
@Param('projectName') projectName: string
71-
): Promise<ProjectDefinition> {
72-
let project: ProjectDefinition | undefined;
73-
74-
try {
75-
project = await this.workspaceService.readWorkspaceProject(projectName);
76-
} catch (err) {
77-
this.logger.error(err);
78-
79-
throw new InternalServerErrorException();
80-
}
81-
82-
if (!project) {
83-
throw new NotFoundException();
84-
}
66+
): Promise<ProjectDto> {
67+
return this.workspaceService.readWorkspaceProject(projectName);
68+
}
8569

86-
return project;
70+
@Patch('project/:projectName')
71+
async updateProject(
72+
@Param('projectName') projectName: string,
73+
@Body() updateProjectDto: UpdateProjectDto
74+
): Promise<ProjectDto> {
75+
return await this.workspaceService.updateWorkspaceProject(
76+
projectName,
77+
updateProjectDto
78+
);
8779
}
8880

89-
@Get(':projectName/target-names')
81+
@Get('project/:projectName/target-names')
9082
getProjectTargetNames(
9183
@Param('projectName') projectName: string
9284
): Promise<string[]> {
93-
try {
94-
return this.workspaceService.readWorkspaceProjectTargetNames(projectName);
95-
} catch (err) {
96-
this.logger.error(err);
97-
98-
throw new InternalServerErrorException();
99-
}
85+
return this.workspaceService.readWorkspaceProjectTargetNames(projectName);
10086
}
10187

102-
@Get(':projectName/target/:targetName')
88+
@Get('project/:projectName/target/:targetName')
10389
async getProjectTarget(
10490
@Param('projectName') projectName: string,
10591
@Param('targetName') targetName: string
10692
): Promise<TargetDefinition> {
107-
let target: TargetDefinition | undefined;
108-
109-
try {
110-
target = await this.workspaceService.readWorkspaceProjectTarget(
111-
projectName,
112-
targetName
113-
);
114-
} catch (err) {
115-
this.logger.error(err);
116-
117-
throw new InternalServerErrorException();
118-
}
119-
120-
if (!target) {
121-
throw new NotFoundException();
122-
}
123-
124-
return target;
93+
return await this.workspaceService.readWorkspaceProjectTarget(
94+
projectName,
95+
targetName
96+
);
12597
}
12698

12799
private ngNewArgsFromDto({ name, options }: WorkspaceCreateDto): string[] {

‎apps/cli-daemon/src/app/workspace/workspace.service.ts‎

Lines changed: 104 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { NodeJsSyncHost } from '@angular-devkit/core/node';
22
import {
33
createWorkspaceHost,
44
readWorkspace as devKitReadWorkspace,
5+
writeWorkspace as devKitWriteWorkspace,
56
ProjectDefinition,
67
TargetDefinition,
78
WorkspaceDefinition,
89
} from '@angular-devkit/core/src/workspace';
910
import {
1011
BadRequestException,
12+
HttpException,
1113
Injectable,
1214
InternalServerErrorException,
1315
Logger,
@@ -16,73 +18,143 @@ import {
1618

1719
import { SessionService } from '../session/session.service';
1820

21+
import { ProjectDto, UpdateProjectDto } from './dto';
1922
import {
2023
ANGULAR_WORKSPACE_NOT_FOUND_EXCEPTION,
2124
BAD_PATH_EXCEPTION,
2225
NOT_ANGULAR_WORKSPACE_EXCEPTION,
2326
} from './entities';
2427

25-
export const ng = 'npx ng new';
28+
const ANGULAR_JSON = '/angular.json';
2629

2730
@Injectable()
2831
export class WorkspaceService {
2932
private readonly logger = new Logger(WorkspaceService.name);
30-
readonly ng = ng;
33+
private readonly nodeJsSyncHost = new NodeJsSyncHost();
34+
3135
constructor(private sessionService: SessionService) {}
3236

33-
async readWorkspace(path: string): Promise<WorkspaceDefinition> {
37+
async isAngularWorkspace(path: string): Promise<boolean> {
3438
try {
35-
return (
36-
await devKitReadWorkspace(
37-
path,
38-
createWorkspaceHost(new NodeJsSyncHost())
39-
)
40-
).workspace;
39+
return !!(await devKitReadWorkspace(
40+
path,
41+
createWorkspaceHost(this.nodeJsSyncHost)
42+
));
43+
} catch {
44+
return false;
45+
}
46+
}
47+
48+
async connect(path: string): Promise<void> {
49+
try {
50+
await devKitReadWorkspace(path, createWorkspaceHost(this.nodeJsSyncHost));
51+
this.sessionService.setCwd(path);
4152
// eslint-disable-next-line @typescript-eslint/no-explicit-any
4253
} catch (err: any) {
43-
const errorMessage = err['message'];
44-
switch (errorMessage) {
45-
case BAD_PATH_EXCEPTION:
46-
throw new BadRequestException(BAD_PATH_EXCEPTION);
47-
case NOT_ANGULAR_WORKSPACE_EXCEPTION:
48-
throw new NotFoundException(ANGULAR_WORKSPACE_NOT_FOUND_EXCEPTION);
49-
default:
50-
this.logger.error(errorMessage);
51-
throw new InternalServerErrorException(err);
52-
}
54+
throw this.handleReadWorkspaceException(err);
5355
}
5456
}
5557

5658
async readWorkspaceProjectNames(): Promise<string[]> {
57-
const workspace = await this.readWorkspace(this.sessionService.cwd);
59+
const workspaceDefinition = await this.readWorkspaceDefinition();
5860

59-
return Array.from(workspace.projects.keys());
61+
return Array.from(workspaceDefinition.projects.keys());
6062
}
6163

62-
async readWorkspaceProject(
63-
name: string
64-
): Promise<ProjectDefinition | undefined> {
65-
const workspace = await this.readWorkspace(this.sessionService.cwd);
64+
async readWorkspaceProject(name: string): Promise<ProjectDto> {
65+
return new ProjectDto(await this.readProjectDefinition(name));
66+
}
67+
68+
async updateWorkspaceProject(
69+
name: string,
70+
updateProjectDto: UpdateProjectDto
71+
): Promise<ProjectDto> {
72+
const workspaceDefinition = await this.readWorkspaceDefinition();
73+
const projectDefinition = workspaceDefinition.projects.get(name);
74+
75+
if (!projectDefinition) {
76+
throw new NotFoundException(`Project ${name} not found`);
77+
}
78+
79+
Object.assign(projectDefinition, updateProjectDto);
80+
await this.writeWorkspace(workspaceDefinition);
6681

67-
return workspace?.projects?.get(name);
82+
return this.readWorkspaceProject(name);
6883
}
6984

7085
async readWorkspaceProjectTargetNames(name: string): Promise<string[]> {
71-
const project = await this.readWorkspaceProject(name);
86+
const projectDefinition = await this.readProjectDefinition(name);
7287

73-
if (!project?.targets?.size) {
88+
if (!projectDefinition?.targets?.size) {
7489
return [];
7590
}
7691

77-
return Array.from(project.targets.keys());
92+
return Array.from(projectDefinition.targets.keys());
7893
}
7994

8095
async readWorkspaceProjectTarget(
8196
projectName: string,
8297
targetName: string
83-
): Promise<TargetDefinition | undefined> {
84-
const project = await this.readWorkspaceProject(projectName);
98+
): Promise<TargetDefinition> {
99+
const projectDefinition = await this.readProjectDefinition(projectName);
100+
const targetDefinition = projectDefinition.targets.get(targetName);
101+
102+
if (!targetDefinition) {
103+
throw new NotFoundException(`Target ${targetName} not found`);
104+
}
105+
106+
return targetDefinition;
107+
}
85108

86-
return project?.targets.get(targetName);
109+
private async readWorkspaceDefinition(): Promise<WorkspaceDefinition> {
110+
try {
111+
return (
112+
await devKitReadWorkspace(
113+
this.sessionService.cwd,
114+
createWorkspaceHost(this.nodeJsSyncHost)
115+
)
116+
).workspace;
117+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
118+
} catch (err: any) {
119+
throw this.handleReadWorkspaceException(err);
120+
}
121+
}
122+
123+
private async writeWorkspace(
124+
workspaceDefinition: WorkspaceDefinition
125+
): Promise<void> {
126+
await devKitWriteWorkspace(
127+
workspaceDefinition,
128+
createWorkspaceHost(this.nodeJsSyncHost),
129+
`${this.sessionService.cwd}${ANGULAR_JSON}`
130+
);
131+
}
132+
133+
private async readProjectDefinition(
134+
name: string
135+
): Promise<ProjectDefinition> {
136+
const workspaceDefinition = await this.readWorkspaceDefinition();
137+
const projectDefinition = workspaceDefinition.projects.get(name);
138+
139+
if (!projectDefinition) {
140+
throw new NotFoundException(`Project ${name} not found`);
141+
}
142+
143+
return projectDefinition;
144+
}
145+
146+
private handleReadWorkspaceException(err: {
147+
message: string;
148+
}): HttpException {
149+
const errorMessage = err['message'];
150+
switch (errorMessage) {
151+
case BAD_PATH_EXCEPTION:
152+
return new BadRequestException(BAD_PATH_EXCEPTION);
153+
case NOT_ANGULAR_WORKSPACE_EXCEPTION:
154+
return new NotFoundException(ANGULAR_WORKSPACE_NOT_FOUND_EXCEPTION);
155+
default:
156+
this.logger.error(errorMessage);
157+
return new InternalServerErrorException(err);
158+
}
87159
}
88160
}

‎libs/shared/data/src/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from './lib/exec-result.interface';
22
export * from './lib/generate-component-args.interface';
33
export * from './lib/directory.interface';
44
export * from './lib/local-storage-keys.consts';
5+
export * from './lib/workspace';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './update-project.dto';
2+
export * from './project';
3+
export * from './target';
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { JsonValue } from '@angular-devkit/core';
2+
3+
export interface Project {
4+
root: string;
5+
prefix?: string;
6+
sourceRoot?: string;
7+
extensions: Record<string, JsonValue | undefined>;
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { JsonValue } from '@angular-devkit/core';
2+
3+
export interface Target {
4+
options?: Record<string, JsonValue | undefined>;
5+
configurations?: Record<
6+
string,
7+
Record<string, JsonValue | undefined> | undefined
8+
>;
9+
defaultConfiguration?: string;
10+
builder: string;
11+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export interface IUpdateProjectDto {
2+
root?: string;
3+
prefix?: string;
4+
sourceRoot?: string;
5+
}

0 commit comments

Comments
 (0)