CHORE: setup
All checks were successful
Quality Check / Linting (push) Successful in 23s
Build Application / build (push) Successful in 33s
Build Application / build-docker (push) Successful in 9s
Build Application / release (push) Successful in 4s

This commit is contained in:
Snoweuph 2025-02-02 20:20:06 +01:00
commit 1ad1418023
Signed by: snoweuph
GPG key ID: BEFC41DA223CEC55
38 changed files with 17196 additions and 0 deletions

View file

@ -0,0 +1,29 @@
name: Feature
title: '[Feature]: '
about: 'Vorlage Für ein Feature Ticket'
ref: 'trunk'
body:
- type: input
id: ticket
attributes:
label: Ticket
description: Für Welches Ticket ist diese Pull Request?
placeholder: TD-1
validations:
required: true
- type: textarea
id: beschreibung
attributes:
label: Beschreibung
description: Was hast du genau gemacht in diesem Ticket?
placeholder: ...
validations:
required: true
- type: textarea
id: more
attributes:
label: Weitere Infos
description: Gibt es noch etwas das ich wissen muss um das Ticket zu Reviewn?
placeholder: ...
validations:
required: false

View file

@ -0,0 +1,3 @@
FROM httpd:2.4
ADD web /usr/local/apache2/htdocs/

View file

@ -0,0 +1,84 @@
name: Build Application
on:
push:
tags:
- 'v[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?'
- 'v*'
jobs:
build:
runs-on: stable
container:
image: git.euph.dev/actions/runner-java-21:latest
steps:
- name: "Checkout"
uses: "https://git.euph.dev/actions/checkout@v3"
- name: "Install Angular CLI"
run: sudo npm i -g @angular/cli
- name: "Install Dependencies"
run: npm ci
- name: Build Bundle
run: ng build
- name: Upload Binary as Artifact
uses: "https://git.euph.dev/actions/upload-artifact@v3"
with:
name: web
path: dist/tower-defence-companion/browser/*
build-docker:
runs-on: docker
needs:
- build
steps:
- name: "Checkout"
uses: "https://git.euph.dev/actions/checkout@v3"
- name: Download artifact from previous job
uses: "https://git.euph.dev/actions/download-artifact@v3"
with:
name: web
path: .forgejo/workflows/web
- name: Login to Registry
uses: "https://git.euph.dev/actions/docker-login@v3"
with:
registry: git.euph.dev
username: ${{ secrets.DEPLOY_USER }}
password: ${{ secrets.DEPLOY_SECRET }}
- name: Build and push Web Image
uses: "https://git.euph.dev/actions/docker-build-push@v5"
with:
context: ".forgejo/workflows/"
push: true
tags: |
git.euph.dev/towerdefence/web-companion:${{ github.ref_name }}
${{ contains(github.ref_name, 'rc') == false && 'git.euph.dev/towerdefence/web-companion:latest' || '' }}
release:
runs-on: stable
container:
image: git.euph.dev/actions/runner-basic:latest
needs:
- build
- build-docker
steps:
- name: Create Empty Release Asset Dir
run: mkdir -p tmp/this/dir/does/not/exist/yet
- name: Create Release
uses: "https://git.euph.dev/actions/release@v2"
with:
direction: upload
tag: ${{ github.ref_name }}
token: ${{ secrets.DEPLOY_TOKEN }}
prerelease: ${{ contains( github.ref_name, "rc") }}
release-dir: tmp/this/dir/does/not/exist/yet
release-notes: |
# Tower Defence - Companion ${{ github.ref_name }}
Run this release with docker like this:
\`\`\`sh
docker run --rm -p 4300:80 git.euph.dev/towerdefence/web-companion:${{ github.ref_name }}
\`\`\`
It will be available under [\`localhost:4300\`](localhost:4300)
<br><br>
For more information read the [Documentation](https://git.euph.dev/TowerDefence/Dokumentation/wiki/Companion/Config)

28
.forgejo/workflows/qs.yml Normal file
View file

@ -0,0 +1,28 @@
name: "Quality Check"
on:
- push
- pull_request
jobs:
linting:
name: "Linting"
runs-on: stable
container:
image: "git.euph.dev/actions/runner-basic:latest"
steps:
- name: "Checkout"
uses: "https://git.euph.dev/actions/checkout@v3"
- uses: actions/cache@v3
with:
path: ~/.node_modules
key: ${{ runner.os }}-${{ hashFiles('package-lock.json', 'eslint.config.mjs', '.stylelintrc', '.stylelintignore') }}
restore-keys: ${{ runner.os }}-
- name: "NPM install"
run: npm i
- name: "Linting TS"
run: npm run lint:ts
- name: "Linting SCSS"
run: npm run lint:scss

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
* text=auto eol=lf

42
.gitignore vendored Normal file
View 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/*
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
# Generated
src/app/core/server/**/*
openapitools.json

1
.prettierignore Normal file
View file

@ -0,0 +1 @@
*

3
.stylelintignore Normal file
View file

@ -0,0 +1,3 @@
*.*
!*.css
!*.scss

14
.stylelintrc.json Normal file
View file

@ -0,0 +1,14 @@
{
"extends": "stylelint-config-standard-scss",
"plugins": [
"stylelint-scss"
],
"rules": {
"custom-property-empty-line-before": null,
"declaration-empty-line-before": null,
"media-feature-range-notation": null,
"import-notation": "string",
"scss/no-global-function-names": null,
"no-empty-source": null
}
}

13
Justfile Normal file
View file

@ -0,0 +1,13 @@
_choose:
just --choose
up:
docker compose up -d
ng serve
down:
docker compose down
lint:
-npm run lint:ts:fix
-npm run lint:scss:fix

1
License.md Normal file
View file

@ -0,0 +1 @@
See License [here](https://git.euph.dev/TowerDefence/.profile/src/branch/main/License.md)

3
Readme.md Normal file
View file

@ -0,0 +1,3 @@
[![QS Badge](https://git.euph.dev/TowerDefence/Companion/actions/workflows/qs.yml/badge.svg?branch=trunk&style=for-the-badge&label=QS)](https://git.euph.dev/TowerDefence/Companion/actions?workflow=qs.yml)
[![Build Badge](https://git.euph.dev/TowerDefence/Companion/actions/workflows/build.yml/badge.svg?style=for-the-badge&label=Build)](https://git.euph.dev/TowerDefence/Companion/actions?workflow=build.yml)
# Tower Defence - Companion

102
angular.json Normal file
View file

@ -0,0 +1,102 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"Tower-Defence-Companion": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/tower-defence-companion",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": [
"zone.js"
],
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": [
"src/styles.scss"
],
"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": "Tower-Defence-Companion:build:production"
},
"development": {
"buildTarget": "Tower-Defence-Companion: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",
"inlineStyleLanguage": "scss",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
}
}
}
}
}

63
eslint.config.mjs Normal file
View file

@ -0,0 +1,63 @@
import simpleImportSort from "eslint-plugin-simple-import-sort";
import typescriptEslint from "@typescript-eslint/eslint-plugin";
import globals from "globals";
import tsParser from "@typescript-eslint/parser";
import path from "node:path";
import {fileURLToPath} from "node:url";
import js from "@eslint/js";
import {FlatCompat} from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
export default [
{
ignores: ["src/app/core/server"],
},
...compat.extends("eslint:recommended", "plugin:@typescript-eslint/strict"),
{
plugins: {
"simple-import-sort": simpleImportSort,
"@typescript-eslint": typescriptEslint,
},
languageOptions: {
globals: {
...globals.browser,
},
parser: tsParser,
ecmaVersion: "latest",
sourceType: "module",
},
rules: {
indent: ["error", 4],
"linebreak-style": ["error", "unix"],
quotes: ["error", "single"],
semi: ["error", "always"],
strict: "error",
"array-bracket-newline": "error",
yoda: "error",
"@typescript-eslint/array-type": [
"error",
{
default: "generic",
},
],
"@typescript-eslint/ban-tslint-comment": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-extraneous-class": "off",
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"no-mixed-spaces-and-tabs": "off",
},
},
]

16280
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

56
package.json Normal file
View file

@ -0,0 +1,56 @@
{
"name": "tower-defence-companion",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"lint:ts": "eslint src",
"lint:scss": "stylelint src",
"lint:ts:fix": "eslint src --fix",
"lint:scss:fix": "stylelint src --fix"
},
"private": true,
"dependencies": {
"@angular/animations": "^19.0.0",
"@angular/common": "^19.0.0",
"@angular/compiler": "^19.0.0",
"@angular/core": "^19.0.0",
"@angular/forms": "^19.0.0",
"@angular/material": "^19.1.2",
"@angular/platform-browser": "^19.0.0",
"@angular/platform-browser-dynamic": "^19.0.0",
"@angular/router": "^19.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^19.0.5",
"@angular/cli": "^19.0.5",
"@angular/compiler-cli": "^19.0.0",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.19.0",
"@types/jasmine": "~5.1.0",
"@typescript-eslint/eslint-plugin": "^8.22.0",
"@typescript-eslint/parser": "^8.22.0",
"eslint": "^9.19.0",
"eslint-plugin-autofix": "^2.2.0",
"eslint-plugin-simple-import-sort": "^12.1.1",
"globals": "^15.14.0",
"jasmine-core": "~5.4.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",
"stylelint": "^16.14.1",
"stylelint-config-standard-scss": "^14.0.0",
"stylelint-scss": "^6.11.0",
"typescript": "~5.6.2"
},
"api_version": "v0.0.0-rc.2",
"volta": {
"node": "22.13.1"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,6 @@
<app-header></app-header>
<app-notification-box></app-notification-box>
<main>
<h1>{{title.getTitle()}}</h1>
<router-outlet />
</main>

View file

@ -0,0 +1,24 @@
app-header {
width: 100%;
}
main {
flex-grow: 1;
min-width: 100%;
width: fit-content;
box-sizing: border-box;
padding: 2rem;
@media (min-width: 60rem) {
width: 80%;
min-width: 60rem;
max-width: 80rem;
}
@media (max-width: 800px) {
width: 100%;
min-width: 100%;
max-width: 100%;
padding: 0.5rem;
}
}

15
src/app/app.component.ts Normal file
View file

@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { RouterOutlet } from '@angular/router';
import { HeaderComponent } from '@app/header/header.component';
import { NotificationBoxComponent } from '@app/notification-box/notification-box.component';
@Component({
selector: 'app-root',
imports: [RouterOutlet, HeaderComponent, NotificationBoxComponent],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent {
constructor(public title: Title) { }
}

15
src/app/app.config.ts Normal file
View file

@ -0,0 +1,15 @@
import { provideHttpClient } from '@angular/common/http';
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideAnimationsAsync(),
provideRouter(routes),
provideHttpClient(),
]
};

4
src/app/app.routes.ts Normal file
View file

@ -0,0 +1,4 @@
import { Routes } from '@angular/router';
import { DashboardComponent } from '@app/views/dashboard/dashboard.component';
export const routes: Routes = [{ path: '', component: DashboardComponent, title: 'Home' }];

View file

@ -0,0 +1,37 @@
import { Injectable } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
export interface Notification {
msg: string;
type: NotificationType;
}
export enum NotificationType {
Information = 'info',
Error = 'error',
}
export type NotificationCallback = (notification: Notification) => void;
@Injectable({ providedIn: 'root' })
export class NotificationService {
private readonly bus: Subject<Notification> = new Subject();
private readonly subscribers: Map<string, Subscription> = new Map<string, Subscription>();
subscribe(subscriberId: string, callback: NotificationCallback): void {
this.subscribers.set(
subscriberId,
this.bus.subscribe({
next: callback
})
);
}
publish(msg: string, type: NotificationType = NotificationType.Information) {
this.bus.next({ msg, type });
}
unsubscribe(subscriberId: string) {
this.subscribers.get(subscriberId)?.unsubscribe();
}
}

View file

@ -0,0 +1,11 @@
<mat-toolbar class="header">
<nav>
<a routerLink="" mat-button>
<mat-icon>smartphone</mat-icon>
Tower Defence Companion
</a>
@for (route of routes; track route) {
<a mat-button routerLink="{{ route.path }}" class="{{ route.class }}">{{ route.title }}</a>
}
</nav>
</mat-toolbar>

View file

@ -0,0 +1,45 @@
.header {
margin: 0;
padding: 0.5rem 1rem;
z-index: 100;
height: fit-content;
background-color: var(--mat-sys-primary-container);
nav {
display: flex;
height: fit-content;
width: 100%;
margin: 0;
box-sizing: border-box;
list-style: none;
gap: 0.25rem;
@media (max-width: 800px) {
a:first-of-type {
display: none;
}
}
}
a,
button {
color: var(--mat-sys-primary);
&:hover,
&.active {
background-color: var(--mat-sys-primary-overlay)
}
}
&__login {
min-width: fit-content;
}
@media (max-width: 500px) {
>a:last-of-type {
display: none;
}
}
}

View file

@ -0,0 +1,42 @@
import { Component, OnInit } from '@angular/core';
import { MatAnchor } from '@angular/material/button';
import { MatIcon } from '@angular/material/icon';
import { MatToolbar } from '@angular/material/toolbar';
import { EventType, Router, RouterLink } from '@angular/router';
@Component({
selector: 'app-header',
imports: [
MatToolbar,
MatAnchor,
RouterLink,
MatIcon,
],
templateUrl: './header.component.html',
styleUrl: './header.component.scss'
})
export class HeaderComponent implements OnInit {
routes: Array<{ path: string, title: string, class: string }> = [];
constructor(
private router: Router,
) {
}
ngOnInit(): void {
const routes = this.router.config
.filter(route => !route.path?.includes(':'))
.filter(route => !route.path?.includes('/'));
this.router.events.subscribe((event) => {
if (event.type != EventType.NavigationEnd) {
return;
}
this.routes = routes.map(route => ({
path: `/${route.path}`,
title: route.title as string,
class: `/${route.path}` == event.url ? 'active' : ''
}));
});
}
}

View file

@ -0,0 +1,7 @@
<div class="notification-box">
@for (notification of notifications.values(); track notification){
<mat-card class="notification-box__card {{notification.type}}" [@slideInOut]>
<mat-card-content>{{notification.msg}}</mat-card-content>
</mat-card>
}
</div>

View file

@ -0,0 +1,36 @@
.notification-box {
position: absolute;
z-index: 100;
right: 0;
top: 3.5rem; // Header Height
width: 15%;
min-width: 20rem;
display: flex;
flex-direction: column;
padding: 0.5rem;
gap: 0.5rem;
@media (max-width: 20rem) {
min-width: calc(100% - 0.5rem);
padding: 0.25rem;
}
overflow: hidden;
&__card {
width: 100%;
box-sizing: border-box;
&.info {
color: var(--mat-sys-tertiary);
background-color: var(--mat-sys-tertiary-container);
}
&.error {
color: var(--mat-sys-error);
background-color: var(--mat-sys-error-container);
}
}
}

View file

@ -0,0 +1,41 @@
import { animate, style, transition, trigger } from '@angular/animations';
import { Component, OnInit } from '@angular/core';
import { MatCardModule } from '@angular/material/card';
import { Notification, NotificationService } from '@core/notification/notification.service';
const NOTIFICATION_TTL = 3000;
@Component({
selector: 'app-notification-box',
imports: [MatCardModule],
animations: [
trigger('slideInOut', [
transition(':enter', [
style({ transform: 'translateX(100%)' }),
animate('200ms ease-in-out', style({ transform: 'translateX(0)' })),
]),
transition(':leave', [animate('200ms ease-in-out', style({ transform: 'translateX(100%)' })),])
]),
],
templateUrl: './notification-box.component.html',
styleUrl: './notification-box.component.scss'
})
export class NotificationBoxComponent implements OnInit {
notifications: Map<number, Notification> = new Map();
constructor(private notificationService: NotificationService) {
}
ngOnInit(): void {
this.notificationService.subscribe('notification-box', this.onNotification.bind(this));
}
onNotification(notification: Notification): void {
const now = Date.now();
this.notifications.set(now, notification);
setTimeout(() => {
this.notifications.delete(now);
}, NOTIFICATION_TTL);
}
}

View file

@ -0,0 +1,3 @@
<div class="dashboard">
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Facere illo animi quidem repellat perspiciatis, excepturi amet corrupti ipsa sit consequuntur placeat ratione saepe velit asperiores suscipit esse quod minima exercitationem minus, alias laudantium inventore! Beatae cum nobis error suscipit cupiditate, praesentium itaque ut ipsa iusto in doloribus unde quisquam consequuntur.</p>
</div>

View file

@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-dashboard',
imports: [],
templateUrl: './dashboard.component.html',
styleUrl: './dashboard.component.scss'
})
export class DashboardComponent {
}

15
src/index.html Normal file
View file

@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tower Defence - Companion</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body class="mat-typography">
<app-root></app-root>
</body>
</html>

6
src/main.ts Normal file
View file

@ -0,0 +1,6 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from '@app/app.component';
import { appConfig } from '@app/app.config';
bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err));

82
src/styles.scss Normal file
View file

@ -0,0 +1,82 @@
@use '@angular/material' as mat;
html,
body {
height: 100%;
min-height: 100%;
margin: 0;
background: var(--mat-sys-surface);
color: var(--mat-sys-on-surface);
--mat-sys-primary-overlay: color-mix(in srgb, var(--mat-sys-primary) 10%, transparent);
color-scheme: light dark;
font-family: var(--mat-sys-label-medium-font);
@include mat.theme((
color: mat.$azure-palette,
typography: Roboto,
density: 0
));
}
app-root {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.mdc-button,
.mdc-fab {
&.abort,
&.error,
&.warn {
$ripple: var(color-mix(in srgb, var(--mat-sys-on-error) calc(var(--mat-sys-pressed-state-layer-opacity) * 100%), transparent));
$fg: var(--mat-sys-on-error);
$bg: var(--mat-sys-error);
$fg-container: var(--mat-sys-on-error-container);
$bg-container: var(--mat-sys-error-container);
@include mat.button-overrides((
// default
text-label-text-color: $bg,
text-ripple-color: $ripple,
text-state-layer-color: $bg,
// filled
filled-label-text-color: $fg,
filled-container-color: $bg,
filled-ripple-color: $ripple,
filled-state-layer-color: $fg,
));
@include mat.fab-overrides((
// default
container-color: $bg-container,
foreground-color: $fg-container,
state-layer-color: $fg-container,
ripple-color: $ripple,
// mini
small-container-color: $bg-container,
small-foreground-color: $fg-container,
small-state-layer-color: $fg-container,
small-ripple-color: $ripple
));
}
}
.mdc-fab.shadowless {
@include mat.fab-overrides((
// default
container-elevation-shadow: transparent,
hover-container-elevation-shadow: transparent,
pressed-container-elevation-shadow: transparent,
focus-container-elevation-shadow: transparent,
// mini
small-container-elevation-shadow: transparent,
small-hover-container-elevation-shadow: transparent,
small-pressed-container-elevation-shadow: transparent,
small-focus-container-elevation-shadow: transparent,
));
}

15
tsconfig.app.json Normal file
View 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"
]
}

43
tsconfig.json Normal file
View file

@ -0,0 +1,43 @@
/* 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",
"useDefineForClassFields": false,
"lib": [
"ES2022",
"dom"
],
"paths": {
"@/*": [
"./src/*"
],
"@app/*": [
"./src/app/*"
],
"@core/*": [
"./src/app/core/*"
]
}
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}

15
tsconfig.spec.json Normal file
View 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"
]
}