Skip to content

Commit

Permalink
Completed implementation of Solution and refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
mlhaufe authored Jan 11, 2024
1 parent 2bef947 commit fcd1533
Show file tree
Hide file tree
Showing 42 changed files with 512 additions and 423 deletions.
4 changes: 2 additions & 2 deletions src/data/EnvironmentRepository.mts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Environment from '~/domain/Environment.mjs';
import PEGSRepository from './PEGSRepository.mjs';
import StorageRepository from './StorageRepository.mjs';
import EnvironmentToJsonMapper from '~/mappers/EnvironmentToJsonMapper.mjs';
import pkg from '~/../package.json' with { type: 'json' };
import type { SemVerString } from '~/lib/SemVer.mjs';

export default class EnvironmentRepository extends PEGSRepository<Environment> {
export default class EnvironmentRepository extends StorageRepository<Environment> {
constructor(storage: Storage) {
super('environments', storage, new EnvironmentToJsonMapper(pkg.version as SemVerString));
}
Expand Down
4 changes: 2 additions & 2 deletions src/data/GoalsRepository.mts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Goals from '~/domain/Goals.mjs';
import PEGSRepository from './PEGSRepository.mjs';
import StorageRepository from './StorageRepository.mjs';
import GoalsToJsonMapper from '~/mappers/GoalsToJsonMapper.mjs';
import pkg from '~/../package.json' with { type: 'json' };
import type { SemVerString } from '~/lib/SemVer.mjs';

export default class GoalsRepository extends PEGSRepository<Goals> {
export default class GoalsRepository extends StorageRepository<Goals> {
constructor(storage: Storage) {
super('goals', storage, new GoalsToJsonMapper(pkg.version as SemVerString));
}
Expand Down
4 changes: 2 additions & 2 deletions src/data/ProjectRepository.mts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Project from '~/domain/Project.mjs';
import PEGSRepository from './PEGSRepository.mjs';
import StorageRepository from './StorageRepository.mjs';
import ProjectToJsonMapper from '~/mappers/ProjectToJsonMapper.mjs';
import pkg from '~/../package.json' with { type: 'json' };
import type { SemVerString } from '~/lib/SemVer.mjs';

export default class ProjectRepository extends PEGSRepository<Project> {
export default class ProjectRepository extends StorageRepository<Project> {
constructor(storage: Storage) {
super('projects', storage, new ProjectToJsonMapper(pkg.version as SemVerString));
}
Expand Down
4 changes: 2 additions & 2 deletions src/data/PEGSRepository.mts → src/data/SlugRepository.mts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type PEGS from '~/domain/PEGS.mjs';
import type SlugEntity from '~/domain/SlugEntity.mjs';
import StorageRepository from './StorageRepository.mjs';
import type Mapper from '~/usecases/Mapper.mjs';
import type { EntityJson } from '~/mappers/EntityToJsonMapper.mjs';

export default abstract class PEGSRepository<E extends PEGS> extends StorageRepository<E> {
export default abstract class SlugRepository<E extends SlugEntity> extends StorageRepository<E> {
constructor(storageKey: string, storage: Storage, mapper: Mapper<E, EntityJson>) {
super(storageKey, storage, mapper);
}
Expand Down
11 changes: 11 additions & 0 deletions src/data/SolutionRepository.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type Solution from '~/domain/Solution.mjs';
import SolutionToJsonMapper from '~/mappers/SolutionToJsonMapper.mjs';
import pkg from '~/../package.json' with { type: 'json' };
import type { SemVerString } from '~/lib/SemVer.mjs';
import SlugRepository from './SlugRepository.mjs';

export default class SolutionRepository extends SlugRepository<Solution> {
constructor(storage: Storage) {
super('solution', storage, new SolutionToJsonMapper(pkg.version as SemVerString));
}
}
11 changes: 11 additions & 0 deletions src/data/SystemRepository.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type System from '~/domain/System.mjs';
import type { SemVerString } from '~/lib/SemVer.mjs';
import StorageRepository from './StorageRepository.mjs';
import pkg from '~/../package.json' with { type: 'json' };
import SystemToJsonMapper from '~/mappers/SystemToJsonMapper.mjs';

export default class SystemRepository extends StorageRepository<System> {
constructor(storage: Storage) {
super('system', storage, new SystemToJsonMapper(pkg.version as SemVerString));
}
}
8 changes: 4 additions & 4 deletions src/domain/Environment.mts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Uuid } from '~/types/Uuid.mjs';
import PEGS from './PEGS.mjs';
import Entity from './Entity.mjs';
import type { Properties } from '~/types/Properties.mjs';

/**
Expand All @@ -9,11 +9,11 @@ import type { Properties } from '~/types/Properties.mjs';
* An environment describes the application domain and external context in which a
* system operates.
*/
export default class Environment extends PEGS {
glossary: Uuid[];
export default class Environment extends Entity {
glossaryIds: Uuid[];

constructor(options: Properties<Environment>) {
super(options);
this.glossary = options.glossary;
this.glossaryIds = options.glossaryIds;
}
}
20 changes: 10 additions & 10 deletions src/domain/Goals.mts
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
import type { Properties } from '~/types/Properties.mjs';
import type { Uuid } from '~/types/Uuid.mjs';
import PEGS from './PEGS.mjs';
import Entity from './Entity.mjs';

/**
* Goals are the needs and wants of an organization.
* They are the things that the organization wants to achieve.
*/
export default class Goals extends PEGS {
export default class Goals extends Entity {
/**
* Functional behaviors specify what results or effects are expected from the system.
* They specify "what" the system should do, not "how" it should do it.
*/
functionalBehaviors: Uuid[];
functionalBehaviorIds: Uuid[];
objective: string;
outcomes: string;
stakeholders: Uuid[];
stakeholderIds: Uuid[];
situation: string;
useCases: Uuid[];
limits: Uuid[];
useCaseIds: Uuid[];
limitIds: Uuid[];

constructor(options: Properties<Goals>) {
super(options);
this.functionalBehaviors = options.functionalBehaviors;
this.functionalBehaviorIds = options.functionalBehaviorIds;
this.objective = options.objective;
this.outcomes = options.outcomes;
this.stakeholders = options.stakeholders;
this.stakeholderIds = options.stakeholderIds;
this.situation = options.situation;
this.useCases = options.useCases;
this.limits = options.limits;
this.useCaseIds = options.useCaseIds;
this.limitIds = options.limitIds;
}
}
54 changes: 0 additions & 54 deletions src/domain/PEGS.mts

This file was deleted.

5 changes: 2 additions & 3 deletions src/domain/Project.mts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import PEGS from './PEGS.mjs';
import Entity from './Entity.mjs';

/**
* A Project is the set of human processes involved in the planning,
* construction, revision, and operation of an associated system.
* @extends PEGS
*/
export default class Project extends PEGS { }
export default class Project extends Entity { }
45 changes: 45 additions & 0 deletions src/domain/SlugEntity.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { Properties } from '~/types/Properties.mjs';
import slugify from '~/lib/slugify.mjs';
import Entity from './Entity.mjs';

export default class SlugEntity extends Entity {
static readonly maxNameLength = 60;
static readonly maxDescriptionLength = 200;

#name!: string;
#description!: string;

constructor(options: Properties<SlugEntity>) {
super(options);
this.name = options.name;
this.description = options.description;
}

get name(): string {
return this.#name;
}

set name(value: string) {
const trimmed = value.trim(),
Clazz = this.constructor as typeof SlugEntity;
if (trimmed.length >= Clazz.maxNameLength)
throw new Error('Entity name cannot be longer than 60 characters');
this.#name = trimmed;
}

get description(): string {
return this.#description;
}

set description(value: string) {
const trimmed = value.trim(),
Clazz = this.constructor as typeof SlugEntity;
if (trimmed.length >= Clazz.maxDescriptionLength)
throw new Error('Project description cannot be longer than 200 characters');
this.#description = trimmed;
}

slug(): string {
return slugify(this.name);
}
}
15 changes: 15 additions & 0 deletions src/domain/Solution.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { Properties } from '~/types/Properties.mjs';
import type { Uuid } from '~/types/Uuid.mjs';
import SlugEntity from './SlugEntity.mjs';

export default class Solution extends SlugEntity {
projectId!: Uuid;
environmentId!: Uuid;
goalsId!: Uuid;
systemId!: Uuid;

constructor(options: Properties<Solution>) {
super(options);
Object.assign(this, options);
}
}
8 changes: 8 additions & 0 deletions src/domain/System.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { Properties } from '~/types/Properties.mjs';
import Entity from './Entity.mjs';

export default class System extends Entity {
constructor(properties: Properties<System>) {
super(properties);
}
}
5 changes: 5 additions & 0 deletions src/lib/slugify.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default (str: string) =>
str.toLowerCase().trim()
.replace(/\s/g, '-')
.replace(/[^\w-]+/g, '')
.replace(/--+/g, '-');
10 changes: 5 additions & 5 deletions src/mappers/EnvironmentToJsonMapper.mts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type { Uuid } from '~/types/Uuid.mjs';
import PEGSToJsonMapper, { type PEGSJson } from './PEGSToJsonMapper.mjs';
import EntityToJsonMapper, { type EntityJson } from './EntityToJsonMapper.mjs';
import Environment from '~/domain/Environment.mjs';
import SemVer from '~/lib/SemVer.mjs';

export interface EnvironmentJson extends PEGSJson {
glossary: Uuid[];
export interface EnvironmentJson extends EntityJson {
glossaryIds: Uuid[];
}

export default class EnvironmentToJsonMapper extends PEGSToJsonMapper {
export default class EnvironmentToJsonMapper extends EntityToJsonMapper {
override mapFrom(target: EnvironmentJson): Environment {
const version = new SemVer(target.serializationVersion);

Expand All @@ -20,7 +20,7 @@ export default class EnvironmentToJsonMapper extends PEGSToJsonMapper {
override mapTo(source: Environment): EnvironmentJson {
return {
...super.mapTo(source),
glossary: source.glossary
glossaryIds: source.glossaryIds
};
}
}
26 changes: 13 additions & 13 deletions src/mappers/GoalsToJsonMapper.mts
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import type { Uuid } from '~/types/Uuid.mjs';
import PEGSToJsonMapper, { type PEGSJson } from './PEGSToJsonMapper.mjs';
import EntityToJsonMapper, { type EntityJson } from './EntityToJsonMapper.mjs';
import Goals from '~/domain/Goals.mjs';
import SemVer from '~/lib/SemVer.mjs';

export interface GoalsJson extends PEGSJson {
functionalBehaviors: Uuid[];
export interface GoalsJson extends EntityJson {
functionalBehaviorIds: Uuid[];
objective: string;
outcomes: string;
situation: string;
stakeholders: Uuid[];
useCases: Uuid[];
limits: Uuid[];
stakeholderIds: Uuid[];
useCaseIds: Uuid[];
limitIds: Uuid[];
}

export default class GoalsToJsonMapper extends PEGSToJsonMapper {
export default class GoalsToJsonMapper extends EntityToJsonMapper {
override mapFrom(target: GoalsJson): Goals {
const version = new SemVer(target.serializationVersion);

if (version.gte('0.3.0'))
return new Goals({
...target,
useCases: target.useCases ?? [],
limits: target.limits ?? []
useCaseIds: target.useCaseIds ?? [],
limitIds: target.limitIds ?? []
});

throw new Error(`Unsupported serialization version: ${version}`);
Expand All @@ -30,13 +30,13 @@ export default class GoalsToJsonMapper extends PEGSToJsonMapper {
override mapTo(source: Goals): GoalsJson {
return {
...super.mapTo(source),
functionalBehaviors: source.functionalBehaviors,
functionalBehaviorIds: source.functionalBehaviorIds,
objective: source.objective,
outcomes: source.outcomes,
situation: source.situation,
stakeholders: source.stakeholders,
useCases: source.useCases,
limits: source.limits
stakeholderIds: source.stakeholderIds,
useCaseIds: source.useCaseIds,
limitIds: source.limitIds
};
}
}
6 changes: 3 additions & 3 deletions src/mappers/ProjectToJsonMapper.mts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Project from '~/domain/Project.mjs';
import PEGSToJsonMapper, { type PEGSJson } from './PEGSToJsonMapper.mjs';
import EntityToJsonMapper, { type EntityJson } from './EntityToJsonMapper.mjs';
import SemVer from '~/lib/SemVer.mjs';

export interface ProjectJson extends PEGSJson { }
export interface ProjectJson extends EntityJson { }

export default class ProjectToJsonMapper extends PEGSToJsonMapper {
export default class ProjectToJsonMapper extends EntityToJsonMapper {
override mapFrom(target: ProjectJson): Project {
const version = new SemVer(target.serializationVersion);

Expand Down
Loading

0 comments on commit fcd1533

Please sign in to comment.