update
This commit is contained in:
parent
70d54d3384
commit
ba20e7ea18
17
src/09 - Decorators/angular/.editorconfig
Normal file
17
src/09 - Decorators/angular/.editorconfig
Normal file
@ -0,0 +1,17 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
ij_typescript_use_double_quotes = false
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
42
src/09 - Decorators/angular/.gitignore
vendored
Normal file
42
src/09 - Decorators/angular/.gitignore
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
4
src/09 - Decorators/angular/.vscode/extensions.json
vendored
Normal file
4
src/09 - Decorators/angular/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
||||
"recommendations": ["angular.ng-template"]
|
||||
}
|
||||
20
src/09 - Decorators/angular/.vscode/launch.json
vendored
Normal file
20
src/09 - Decorators/angular/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ng serve",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: start",
|
||||
"url": "http://localhost:4200/"
|
||||
},
|
||||
{
|
||||
"name": "ng test",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: test",
|
||||
"url": "http://localhost:9876/debug.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
42
src/09 - Decorators/angular/.vscode/tasks.json
vendored
Normal file
42
src/09 - Decorators/angular/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "(.*?)"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation complete"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "test",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "(.*?)"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation complete"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
59
src/09 - Decorators/angular/README.md
Normal file
59
src/09 - Decorators/angular/README.md
Normal file
@ -0,0 +1,59 @@
|
||||
# DecoratorDemo
|
||||
|
||||
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.1.
|
||||
|
||||
## Development server
|
||||
|
||||
To start a local development server, run:
|
||||
|
||||
```bash
|
||||
ng serve
|
||||
```
|
||||
|
||||
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
||||
|
||||
```bash
|
||||
ng generate component component-name
|
||||
```
|
||||
|
||||
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
||||
|
||||
```bash
|
||||
ng generate --help
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To build the project run:
|
||||
|
||||
```bash
|
||||
ng build
|
||||
```
|
||||
|
||||
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
|
||||
|
||||
```bash
|
||||
ng test
|
||||
```
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
For end-to-end (e2e) testing, run:
|
||||
|
||||
```bash
|
||||
ng e2e
|
||||
```
|
||||
|
||||
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
||||
|
||||
## Additional Resources
|
||||
|
||||
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
||||
99
src/09 - Decorators/angular/angular.json
Normal file
99
src/09 - Decorators/angular/angular.json
Normal file
@ -0,0 +1,99 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"decorator-demo": {
|
||||
"projectType": "application",
|
||||
"schematics": {},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:application",
|
||||
"options": {
|
||||
"outputPath": "dist/decorator-demo",
|
||||
"index": "src/index.html",
|
||||
"browser": "src/main.ts",
|
||||
"polyfills": [
|
||||
"zone.js"
|
||||
],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kB",
|
||||
"maximumError": "1MB"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "4kB",
|
||||
"maximumError": "8kB"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "decorator-demo:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "decorator-demo:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
],
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": "3954409e-ab36-40d8-9254-9dbfbdd3e2e6"
|
||||
}
|
||||
}
|
||||
14476
src/09 - Decorators/angular/package-lock.json
generated
Normal file
14476
src/09 - Decorators/angular/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
37
src/09 - Decorators/angular/package.json
Normal file
37
src/09 - Decorators/angular/package.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "decorator-demo",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "^19.2.0",
|
||||
"@angular/compiler": "^19.2.0",
|
||||
"@angular/core": "^19.2.0",
|
||||
"@angular/forms": "^19.2.0",
|
||||
"@angular/platform-browser": "^19.2.0",
|
||||
"@angular/platform-browser-dynamic": "^19.2.0",
|
||||
"@angular/router": "^19.2.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^19.2.1",
|
||||
"@angular/cli": "^19.2.1",
|
||||
"@angular/compiler-cli": "^19.2.0",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"jasmine-core": "~5.6.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"typescript": "~5.7.2"
|
||||
}
|
||||
}
|
||||
BIN
src/09 - Decorators/angular/public/favicon.ico
Normal file
BIN
src/09 - Decorators/angular/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
7
src/09 - Decorators/angular/src/app/app.component.html
Normal file
7
src/09 - Decorators/angular/src/app/app.component.html
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
<main class="main">
|
||||
<app-greeting name="World 123"></app-greeting>
|
||||
<div>Lorem <span appHighlight="white" bgColor="hotpink">ipsum dolor</span>, sit amet consectetur adipisicing elit. Molestias culpa facilis voluptas dolorum fuga explicabo possimus consequuntur. Impedit amet sint, adipisci architecto animi distinctio officiis praesentium. Praesentium cumque sapiente dolorem!</div>
|
||||
</main>
|
||||
|
||||
<router-outlet />
|
||||
29
src/09 - Decorators/angular/src/app/app.component.spec.ts
Normal file
29
src/09 - Decorators/angular/src/app/app.component.spec.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AppComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have the 'decorator-demo' title`, () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app.title).toEqual('decorator-demo');
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, decorator-demo');
|
||||
});
|
||||
});
|
||||
14
src/09 - Decorators/angular/src/app/app.component.ts
Normal file
14
src/09 - Decorators/angular/src/app/app.component.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { HighlightDirective } from './directives/highlight.directive';
|
||||
import { GreetingComponent } from './greeting/greeting.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet, GreetingComponent, HighlightDirective],
|
||||
templateUrl: './app.component.html',
|
||||
styleUrl: './app.component.css',
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'decorator-demo';
|
||||
}
|
||||
8
src/09 - Decorators/angular/src/app/app.config.ts
Normal file
8
src/09 - Decorators/angular/src/app/app.config.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)]
|
||||
};
|
||||
3
src/09 - Decorators/angular/src/app/app.routes.ts
Normal file
3
src/09 - Decorators/angular/src/app/app.routes.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
export const routes: Routes = [];
|
||||
@ -0,0 +1,8 @@
|
||||
import { HighlightDirective } from './highlight.directive';
|
||||
|
||||
describe('HighlightDirective', () => {
|
||||
it('should create an instance', () => {
|
||||
const directive = new HighlightDirective();
|
||||
expect(directive).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,27 @@
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
Input,
|
||||
OnChanges,
|
||||
Renderer2,
|
||||
} from '@angular/core';
|
||||
|
||||
@Directive({
|
||||
selector: '[appHighlight]',
|
||||
})
|
||||
export class HighlightDirective implements OnChanges {
|
||||
@Input('appHighlight') highlightColor: string = 'black';
|
||||
@Input() bgColor: string = 'yellow';
|
||||
|
||||
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
||||
|
||||
ngOnChanges(): void {
|
||||
this.renderer.setStyle(this.el.nativeElement, 'color', this.highlightColor);
|
||||
|
||||
this.renderer.setStyle(
|
||||
this.el.nativeElement,
|
||||
'backgroundColor',
|
||||
this.bgColor
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { DataService } from '../services/data.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-greeting',
|
||||
imports: [],
|
||||
template: ` <div>
|
||||
<h1>Hallo, {{ name }}!</h1>
|
||||
<p>{{ data }}</p>
|
||||
</div>`,
|
||||
})
|
||||
export class GreetingComponent implements OnInit {
|
||||
@Input() name: string = 'Gast';
|
||||
|
||||
public data = 'No data';
|
||||
|
||||
constructor(private dataService: DataService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
setTimeout(() => {
|
||||
this.data = this.dataService.getData();
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DataService } from './data.service';
|
||||
|
||||
describe('DataService', () => {
|
||||
let service: DataService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(DataService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
12
src/09 - Decorators/angular/src/app/services/data.service.ts
Normal file
12
src/09 - Decorators/angular/src/app/services/data.service.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DataService {
|
||||
constructor() {}
|
||||
|
||||
getData(): string {
|
||||
return 'Daten aus dem DataService';
|
||||
}
|
||||
}
|
||||
13
src/09 - Decorators/angular/src/index.html
Normal file
13
src/09 - Decorators/angular/src/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>DecoratorDemo</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
6
src/09 - Decorators/angular/src/main.ts
Normal file
6
src/09 - Decorators/angular/src/main.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { appConfig } from './app/app.config';
|
||||
import { AppComponent } from './app/app.component';
|
||||
|
||||
bootstrapApplication(AppComponent, appConfig)
|
||||
.catch((err) => console.error(err));
|
||||
1
src/09 - Decorators/angular/src/styles.css
Normal file
1
src/09 - Decorators/angular/src/styles.css
Normal file
@ -0,0 +1 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
15
src/09 - Decorators/angular/tsconfig.app.json
Normal file
15
src/09 - Decorators/angular/tsconfig.app.json
Normal file
@ -0,0 +1,15 @@
|
||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
"src/main.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
27
src/09 - Decorators/angular/tsconfig.json
Normal file
27
src/09 - Decorators/angular/tsconfig.json
Normal file
@ -0,0 +1,27 @@
|
||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/out-tsc",
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "bundler",
|
||||
"importHelpers": true,
|
||||
"target": "ES2022",
|
||||
"module": "ES2022"
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
15
src/09 - Decorators/angular/tsconfig.spec.json
Normal file
15
src/09 - Decorators/angular/tsconfig.spec.json
Normal file
@ -0,0 +1,15 @@
|
||||
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
67
src/09 - Decorators/demo/README.md
Normal file
67
src/09 - Decorators/demo/README.md
Normal file
@ -0,0 +1,67 @@
|
||||
# Ausführen von TypeScript mit Node.js
|
||||
|
||||
Da die Decorators in Deno derzeit nicht unterstützt werden, zeigen wir hier, wie du dein TypeScript-Projekt mit Node.js ausführst.
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- [Node.js](https://nodejs.org/) installiert
|
||||
- Ein Paketmanager wie npm (wird mit Node.js mitgeliefert)
|
||||
|
||||
## Lokale Installation von TypeScript und ts-node
|
||||
|
||||
1. **Projekt initialisieren**
|
||||
|
||||
Starte in deinem Projektverzeichnis ein neues Node.js-Projekt:
|
||||
|
||||
```bash
|
||||
npm init -y
|
||||
```
|
||||
|
||||
2. **TypeScript und ts-node installieren**
|
||||
|
||||
Installiere `typescript` und `ts-node` als Entwicklungsabhängigkeiten:
|
||||
|
||||
```bash
|
||||
npm install typescript ts-node --save-dev
|
||||
```
|
||||
|
||||
3. **tsconfig.json erstellen**
|
||||
|
||||
Erstelle eine `tsconfig.json` im Projektstamm (falls noch nicht vorhanden) und aktiviere die Option für Decorators:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"module": "ESNext",
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Package-Script anpassen
|
||||
|
||||
Du kannst ein Skript in deiner `package.json` hinzufügen, um dein TypeScript-Programm mit `ts-node` auszuführen. Füge beispielsweise folgenden Abschnitt unter `"scripts"` hinzu:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"start": "ts-node simple-decorators-demo.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Anschließend kannst du dein Programm mit folgendem Befehl starten:
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
## Alternative: Ausführen mit npx
|
||||
|
||||
Falls du `ts-node` nicht dauerhaft im Projekt installieren möchtest, kannst du es auch direkt mit `npx` ausführen:
|
||||
|
||||
```bash
|
||||
npx ts-node demo.ts
|
||||
```
|
||||
93
src/09 - Decorators/demo/decorators-advanced.ts
Normal file
93
src/09 - Decorators/demo/decorators-advanced.ts
Normal file
@ -0,0 +1,93 @@
|
||||
// Property Decorator: Validiert, dass die Property nicht leer ist.
|
||||
function NonEmpty(target: any, propertyKey: string) {
|
||||
let value: string;
|
||||
const getter = function () {
|
||||
return value;
|
||||
};
|
||||
const setter = function (newVal: string) {
|
||||
if (!newVal || newVal.trim() === '') {
|
||||
throw new Error(`Property "${propertyKey}" darf nicht leer sein.`);
|
||||
}
|
||||
value = newVal;
|
||||
};
|
||||
Object.defineProperty(target, propertyKey, {
|
||||
get: getter,
|
||||
set: setter,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Parameter Decorator: Loggt Informationen über die Parameter einer Methode.
|
||||
function LogParameter(
|
||||
target: any,
|
||||
propertyKey: string,
|
||||
parameterIndex: number
|
||||
) {
|
||||
console.log(
|
||||
`Parameter-Dekorator: Methode "${propertyKey}" - Parameter an Position ${parameterIndex} wurde dekoriert.`
|
||||
);
|
||||
// In realen Anwendungen kannst du hier Metadaten speichern.
|
||||
}
|
||||
|
||||
// Accessor Decorator: Loggt den Zugriff auf einen Getter.
|
||||
function LogAccessor(
|
||||
target: any,
|
||||
propertyKey: string,
|
||||
descriptor: PropertyDescriptor
|
||||
) {
|
||||
const originalGet = descriptor.get;
|
||||
if (originalGet) {
|
||||
descriptor.get = function () {
|
||||
console.log(`Accessor "${propertyKey}" wurde aufgerufen.`);
|
||||
return originalGet.call(this);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class AdvancedProduct {
|
||||
@NonEmpty
|
||||
name: string;
|
||||
|
||||
private _price: number;
|
||||
|
||||
constructor(name: string, price: number) {
|
||||
this.name = name; // Validierung über @NonEmpty
|
||||
this._price = price;
|
||||
}
|
||||
|
||||
@LogAccessor
|
||||
get price(): number {
|
||||
return this._price;
|
||||
}
|
||||
|
||||
set price(newPrice: number) {
|
||||
if (newPrice < 0) {
|
||||
throw new Error('Der Preis darf nicht negativ sein.');
|
||||
}
|
||||
this._price = newPrice;
|
||||
}
|
||||
|
||||
// Die Parameter der Methode werden mit @LogParameter dekoriert.
|
||||
updateProduct(@LogParameter newName: string, @LogParameter newPrice: number) {
|
||||
this.name = newName;
|
||||
this.price = newPrice;
|
||||
}
|
||||
}
|
||||
|
||||
// Demo: Erstellen eines Produktes und Ausführen von Methoden
|
||||
const advancedProduct = new AdvancedProduct('Smartphone', 500);
|
||||
|
||||
// Aufruf des Accessors löst Log-Ausgabe aus.
|
||||
console.log('Aktueller Preis:', advancedProduct.price);
|
||||
|
||||
// Aufruf der Methode, bei der die Parameter dekoriert sind.
|
||||
advancedProduct.updateProduct('Premium Smartphone', 750);
|
||||
console.log('Neuer Name:', advancedProduct.name);
|
||||
|
||||
// Test: Versuch, einen leeren Namen zu setzen – dies löst einen Fehler aus.
|
||||
try {
|
||||
advancedProduct.name = '';
|
||||
} catch (error) {
|
||||
console.error('Fehler:', (error as Error).message);
|
||||
}
|
||||
33
src/09 - Decorators/demo/decorators.ts
Normal file
33
src/09 - Decorators/demo/decorators.ts
Normal file
@ -0,0 +1,33 @@
|
||||
// Klassen-Dekorator: Loggt, wenn die Klasse definiert wird.
|
||||
function ClassLogger(target: Function) {
|
||||
console.log(`Klasse ${target.name} wurde definiert.`);
|
||||
}
|
||||
|
||||
// Methoden-Dekorator: Loggt den Aufruf der Methode, ihre Argumente und den Rückgabewert.
|
||||
function MethodLogger(
|
||||
target: any,
|
||||
propertyKey: string,
|
||||
descriptor: PropertyDescriptor
|
||||
) {
|
||||
const originalMethod = descriptor.value;
|
||||
descriptor.value = function (...args: any[]) {
|
||||
console.log(`Methode ${propertyKey} wird aufgerufen mit Argumenten:`, args);
|
||||
const result = originalMethod.apply(this, args);
|
||||
console.log(`Methode ${propertyKey} gibt zurück:`, result);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
@ClassLogger
|
||||
class Person {
|
||||
constructor(private name: string) {}
|
||||
|
||||
@MethodLogger
|
||||
greet(greeting: string): string {
|
||||
return `${greeting}, mein Name ist ${this.name}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Live Demo: Instanziierung und Methodenaufruf
|
||||
const person = new Person('John');
|
||||
console.log(person.greet('Hallo'));
|
||||
96
src/09 - Decorators/demo/index.ts
Normal file
96
src/09 - Decorators/demo/index.ts
Normal file
@ -0,0 +1,96 @@
|
||||
// simple-decorators-demo.ts
|
||||
|
||||
// Klassen-Dekorator
|
||||
function SimpleClassDecorator(constructor: Function) {
|
||||
console.log(
|
||||
'SimpleClassDecorator: Auf Klasse',
|
||||
constructor.name,
|
||||
'angewendet.'
|
||||
);
|
||||
}
|
||||
|
||||
// Methoden-Dekorator
|
||||
function SimpleMethodDecorator(
|
||||
target: any,
|
||||
propertyKey: string,
|
||||
descriptor: PropertyDescriptor
|
||||
) {
|
||||
console.log(
|
||||
`SimpleMethodDecorator: Auf Methode "${propertyKey}" angewendet.`
|
||||
);
|
||||
const originalMethod = descriptor.value;
|
||||
descriptor.value = function (...args: any[]) {
|
||||
console.log(
|
||||
`SimpleMethodDecorator: Methode "${propertyKey}" wurde aufgerufen mit Argumenten:`,
|
||||
args
|
||||
);
|
||||
return originalMethod.apply(this, args);
|
||||
};
|
||||
}
|
||||
|
||||
// Property-Dekorator
|
||||
function SimplePropertyDecorator(target: any, propertyKey: string) {
|
||||
console.log(
|
||||
`SimplePropertyDecorator: Auf Property "${propertyKey}" angewendet.`
|
||||
);
|
||||
}
|
||||
|
||||
// Parameter-Dekorator
|
||||
function SimpleParameterDecorator(
|
||||
target: any,
|
||||
propertyKey: string,
|
||||
parameterIndex: number
|
||||
) {
|
||||
console.log(
|
||||
`SimpleParameterDecorator: Auf Parameter an Position ${parameterIndex} in Methode "${propertyKey}" angewendet.`
|
||||
);
|
||||
}
|
||||
|
||||
// Accessor-Dekorator
|
||||
function SimpleAccessorDecorator(
|
||||
target: any,
|
||||
propertyKey: string,
|
||||
descriptor: PropertyDescriptor
|
||||
) {
|
||||
console.log(
|
||||
`SimpleAccessorDecorator: Auf Accessor "${propertyKey}" angewendet.`
|
||||
);
|
||||
const originalGet = descriptor.get;
|
||||
if (originalGet) {
|
||||
descriptor.get = function () {
|
||||
console.log(
|
||||
`SimpleAccessorDecorator: Getter von "${propertyKey}" wurde aufgerufen.`
|
||||
);
|
||||
return originalGet.call(this);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Anwendung der Dekoratoren in einer Demo-Klasse
|
||||
@SimpleClassDecorator
|
||||
class Demo {
|
||||
@SimplePropertyDecorator
|
||||
demoProperty: string = 'Demo Property';
|
||||
|
||||
private _demoValue: number = 0;
|
||||
|
||||
@SimpleAccessorDecorator
|
||||
get demoValue(): number {
|
||||
return this._demoValue;
|
||||
}
|
||||
set demoValue(val: number) {
|
||||
this._demoValue = val;
|
||||
}
|
||||
|
||||
@SimpleMethodDecorator
|
||||
demoMethod(@SimpleParameterDecorator param: string) {
|
||||
console.log('Innerhalb von demoMethod mit Parameter:', param);
|
||||
}
|
||||
}
|
||||
|
||||
// Demo: Instanz erstellen und Methoden aufrufen
|
||||
const demoInstance = new Demo();
|
||||
demoInstance.demoMethod('Test');
|
||||
console.log('Lese demoValue:', demoInstance.demoValue);
|
||||
demoInstance.demoValue = 42;
|
||||
console.log('Neuer demoValue:', demoInstance.demoValue);
|
||||
233
src/09 - Decorators/demo/package-lock.json
generated
Normal file
233
src/09 - Decorators/demo/package-lock.json
generated
Normal file
@ -0,0 +1,233 @@
|
||||
{
|
||||
"name": "09 - Decorators",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@cspotcode/source-map-support": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "0.3.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
||||
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.0.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tsconfig/node10": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
|
||||
"integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tsconfig/node12": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
||||
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tsconfig/node14": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
||||
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tsconfig/node16": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
||||
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.13.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.9.tgz",
|
||||
"integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~6.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.14.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
||||
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-walk": {
|
||||
"version": "8.3.4",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
|
||||
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"acorn": "^8.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/create-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/make-error": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ts-node": {
|
||||
"version": "10.9.2",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
|
||||
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@cspotcode/source-map-support": "^0.8.0",
|
||||
"@tsconfig/node10": "^1.0.7",
|
||||
"@tsconfig/node12": "^1.0.7",
|
||||
"@tsconfig/node14": "^1.0.0",
|
||||
"@tsconfig/node16": "^1.0.2",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"arg": "^4.1.0",
|
||||
"create-require": "^1.1.0",
|
||||
"diff": "^4.0.1",
|
||||
"make-error": "^1.1.1",
|
||||
"v8-compile-cache-lib": "^3.0.1",
|
||||
"yn": "3.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"ts-node": "dist/bin.js",
|
||||
"ts-node-cwd": "dist/bin-cwd.js",
|
||||
"ts-node-esm": "dist/bin-esm.js",
|
||||
"ts-node-script": "dist/bin-script.js",
|
||||
"ts-node-transpile-only": "dist/bin-transpile.js",
|
||||
"ts-script": "dist/bin-script-deprecated.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/core": ">=1.2.50",
|
||||
"@swc/wasm": ">=1.2.50",
|
||||
"@types/node": "*",
|
||||
"typescript": ">=2.7"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@swc/core": {
|
||||
"optional": true
|
||||
},
|
||||
"@swc/wasm": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.8.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
|
||||
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
|
||||
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/yn": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
src/09 - Decorators/demo/package.json
Normal file
6
src/09 - Decorators/demo/package.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
}
|
||||
14
src/09 - Decorators/demo/tsconfig.json
Normal file
14
src/09 - Decorators/demo/tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Decorator config */
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true
|
||||
}
|
||||
}
|
||||
22
src/11-robo-project/solution/deno.json
Normal file
22
src/11-robo-project/solution/deno.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"tasks": {
|
||||
"cli": "deno run --allow-net src/cli.ts",
|
||||
|
||||
"move:forward": "deno run --allow-net src/cli.ts move forward 50 1",
|
||||
"move:backward": "deno run --allow-net src/cli.ts move backward 50 1",
|
||||
|
||||
"beep": "deno task cli beep",
|
||||
|
||||
"status:on": "deno run --allow-net src/cli.ts statuslight on",
|
||||
"status:off": "deno run --allow-net src/cli.ts statuslight off",
|
||||
|
||||
"light:off": "deno run --allow-net src/cli.ts light off",
|
||||
"light:red": "deno run --allow-net src/cli.ts light red",
|
||||
"light:green": "deno run --allow-net src/cli.ts light green",
|
||||
"light:blue": "deno run --allow-net src/cli.ts light blue"
|
||||
},
|
||||
"imports": {
|
||||
"@std/assert": "jsr:@std/assert@1"
|
||||
}
|
||||
}
|
||||
|
||||
23
src/11-robo-project/solution/deno.lock
generated
Normal file
23
src/11-robo-project/solution/deno.lock
generated
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"version": "4",
|
||||
"specifiers": {
|
||||
"jsr:@std/assert@1": "1.0.11",
|
||||
"jsr:@std/internal@^1.0.5": "1.0.5"
|
||||
},
|
||||
"jsr": {
|
||||
"@std/assert@1.0.11": {
|
||||
"integrity": "2461ef3c368fe88bc60e186e7744a93112f16fd110022e113a0849e94d1c83c1",
|
||||
"dependencies": [
|
||||
"jsr:@std/internal"
|
||||
]
|
||||
},
|
||||
"@std/internal@1.0.5": {
|
||||
"integrity": "54a546004f769c1ac9e025abd15a76b6671ddc9687e2313b67376125650dc7ba"
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"dependencies": [
|
||||
"jsr:@std/assert@1"
|
||||
]
|
||||
}
|
||||
}
|
||||
63
src/11-robo-project/solution/robo.bat
Normal file
63
src/11-robo-project/solution/robo.bat
Normal file
@ -0,0 +1,63 @@
|
||||
@echo off
|
||||
REM
|
||||
if "%~1"=="" (
|
||||
echo Usage: robo.bat [command]
|
||||
echo Beispiel: robo.bat light:green
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
set "cmd=%~1"
|
||||
|
||||
REM
|
||||
if /I "%cmd%"=="cli" (
|
||||
deno run --allow-net src/cli.ts
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
if /I "%cmd%"=="move:forward" (
|
||||
deno run --allow-net src/cli.ts move forward 50 1
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
if /I "%cmd%"=="move:backward" (
|
||||
deno run --allow-net src/cli.ts move backward 50 1
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
if /I "%cmd%"=="beep" (
|
||||
deno task cli beep
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
if /I "%cmd%"=="status:on" (
|
||||
deno run --allow-net src/cli.ts statuslight on
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
if /I "%cmd%"=="status:off" (
|
||||
deno run --allow-net src/cli.ts statuslight off
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
if /I "%cmd%"=="light:off" (
|
||||
deno run --allow-net src/cli.ts light off
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
if /I "%cmd%"=="light:red" (
|
||||
deno run --allow-net src/cli.ts light red
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
if /I "%cmd%"=="light:green" (
|
||||
deno run --allow-net src/cli.ts light green
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
if /I "%cmd%"=="light:blue" (
|
||||
deno run --allow-net src/cli.ts light blue
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
echo Unbekannter Befehl: %cmd%
|
||||
exit /b 1
|
||||
63
src/11-robo-project/solution/src/cli.ts
Normal file
63
src/11-robo-project/solution/src/cli.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { LightColor, setLight } from './core/light.ts';
|
||||
import { MotorDirection, move } from './core/motor.ts';
|
||||
import { beep, StatusLight, statusLight } from './core/robot.ts';
|
||||
|
||||
const args = Deno.args;
|
||||
const command = args[0];
|
||||
|
||||
if (!command) {
|
||||
console.log('Bitte einen Befehl angeben: beep | statuslight | light | move');
|
||||
Deno.exit(1);
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
case 'beep':
|
||||
await beep();
|
||||
break;
|
||||
|
||||
case 'statuslight': {
|
||||
if (args.length < 2) {
|
||||
console.log('Syntax: statuslight <on|off>');
|
||||
Deno.exit(1);
|
||||
}
|
||||
|
||||
const action = args[1] as StatusLight;
|
||||
await statusLight(action);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'light': {
|
||||
let color: LightColor = 'blue';
|
||||
|
||||
if (args.length === 2) {
|
||||
color = args[1] as LightColor;
|
||||
}
|
||||
|
||||
setLight(color);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'move': {
|
||||
if (args.length < 4) {
|
||||
console.log('Syntax: move <forward|backward> <speed> <duration>');
|
||||
Deno.exit(1);
|
||||
}
|
||||
const direction = args[1] as MotorDirection;
|
||||
const speed = Number(args[2]);
|
||||
const durationInSeconds = Number(args[3]);
|
||||
|
||||
move({
|
||||
motorLeft: { direction, speed },
|
||||
motorRight: { direction, speed },
|
||||
durationInSeconds,
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
console.log('Unbekannter Befehl');
|
||||
Deno.exit(1);
|
||||
}
|
||||
44
src/11-robo-project/solution/src/core/light.ts
Normal file
44
src/11-robo-project/solution/src/core/light.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { sendRequest } from '../robot-client.ts';
|
||||
|
||||
export type LED = { red: number; green: number; blue: number };
|
||||
export type LightColor = 'off' | 'red' | 'green' | 'blue';
|
||||
|
||||
const Lights: Record<LightColor, LED> = {
|
||||
off: {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
},
|
||||
red: {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
},
|
||||
blue: {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 255,
|
||||
},
|
||||
green: {
|
||||
red: 0,
|
||||
green: 255,
|
||||
blue: 0,
|
||||
},
|
||||
};
|
||||
|
||||
interface LedState {
|
||||
[key: string]: LED;
|
||||
}
|
||||
|
||||
export async function setLight(color: LightColor): Promise<void> {
|
||||
const light = Lights[color];
|
||||
|
||||
const body: LedState = {
|
||||
led_0: light,
|
||||
led_1: light,
|
||||
led_2: light,
|
||||
led_3: light,
|
||||
};
|
||||
|
||||
await sendRequest('/light', 'POST', body);
|
||||
}
|
||||
16
src/11-robo-project/solution/src/core/motor.ts
Normal file
16
src/11-robo-project/solution/src/core/motor.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { sendRequest } from '../robot-client.ts';
|
||||
|
||||
export type MotorDirection = 'forward' | 'backward';
|
||||
export type MoveRequest = {
|
||||
motorLeft: { direction: MotorDirection; speed: number };
|
||||
motorRight: { direction: MotorDirection; speed: number };
|
||||
durationInSeconds: number;
|
||||
};
|
||||
|
||||
export async function move(body: MoveRequest): Promise<void> {
|
||||
if (body.motorLeft.speed > 100 || body.motorRight.speed > 100) {
|
||||
throw new Error('Speed must be between 0 and 100');
|
||||
}
|
||||
|
||||
await sendRequest('/move', 'POST', body);
|
||||
}
|
||||
11
src/11-robo-project/solution/src/core/robot.ts
Normal file
11
src/11-robo-project/solution/src/core/robot.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { sendRequest } from '../robot-client.ts';
|
||||
|
||||
export type StatusLight = 'on' | 'off';
|
||||
|
||||
export async function beep(): Promise<void> {
|
||||
await sendRequest('/horn/beep', 'GET');
|
||||
}
|
||||
|
||||
export async function statusLight(action: StatusLight): Promise<void> {
|
||||
await sendRequest(`/statuslight/${action}`, 'GET');
|
||||
}
|
||||
31
src/11-robo-project/solution/src/robot-client.ts
Normal file
31
src/11-robo-project/solution/src/robot-client.ts
Normal file
@ -0,0 +1,31 @@
|
||||
type Method = 'GET' | 'POST';
|
||||
|
||||
const buildUrl = (endpoint: string): string => `http://172.20.10.2${endpoint}`;
|
||||
|
||||
export async function sendRequest<T>(
|
||||
endpoint: string,
|
||||
method: Method,
|
||||
body: unknown = null
|
||||
): Promise<void> {
|
||||
try {
|
||||
const options: RequestInit = {
|
||||
method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
};
|
||||
|
||||
if (body) {
|
||||
options.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
const response = await fetch(buildUrl(endpoint), options);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error sending request: ', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
45
src/11-robo-project/solution/test.http
Normal file
45
src/11-robo-project/solution/test.http
Normal file
@ -0,0 +1,45 @@
|
||||
# REST Client - Huachao Mao
|
||||
|
||||
### Get Status Light
|
||||
GET http://172.20.10.2/statuslight/state
|
||||
|
||||
### POST
|
||||
POST http://172.20.10.2/move
|
||||
|
||||
{
|
||||
"motorLeft": {
|
||||
"direction": "forward",
|
||||
"speed": 50
|
||||
},
|
||||
"motorRight": {
|
||||
"direction": "forward",
|
||||
"speed": 20
|
||||
},
|
||||
"durationInSeconds": 3
|
||||
}
|
||||
|
||||
### POST light
|
||||
POST http://172.20.10.2/light
|
||||
|
||||
{
|
||||
"led_0": {
|
||||
"red": 0,
|
||||
"green": 255,
|
||||
"blue": 0
|
||||
},
|
||||
"led_1": {
|
||||
"red": 0,
|
||||
"green": 255,
|
||||
"blue": 0
|
||||
},
|
||||
"led_2": {
|
||||
"red": 0,
|
||||
"green": 255,
|
||||
"blue": 255
|
||||
},
|
||||
"led_3": {
|
||||
"red": 0,
|
||||
"green": 255,
|
||||
"blue": 255
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user