-
-
Notifications
You must be signed in to change notification settings - Fork 187
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add unique script/category IDs $49, $59, $262, $126
This commit is too big, all "supporting changes " should be committed in different commits: 1. Commit I. `Executable` domain concept. - Rename `Node` to `Executable` throughout the codebase. - Create subfolders in `src/domain` for better structure/navigatability. - Ensure TODO.md is addressed and removed from this commit. 3. Commit II (SMALL): Search `TODO: In separate commit trim this data.`, fix it. 2. Commit II. Identifiable pattern (or merge with commit III)? - Use string arbitrary IDs for categories. - Use string IDs for categories instead of using numeric pseudo-IDs. 3. Commit III. Entity - Remove Entity from infrastructure layer to better align with DDD (domain-driven design) as it's a domain concern. - Remove EntityBase for simplicity and to avoid technical nomenclature in names. TODO: - Addd valitaioon to ensure that every script / category has unique ID across collections. - Bug: Standard -> Selected _-> None, when done Standard not being higlighted. - Search `TODO:` fix all. This commit introduces IDs for all categories and scripts. The design provides a foundation for future expansion. Using IDs simplify planned import / export functionality. Key changes: - Add `id:` property for script and categories and parse them in the application. - Add ID validation in collection data with suggestions. - Add utility/helper script to generate missing IDs in collection files. Supporting changes: - Name related interfaces to drop `I` prefix to align with modern conventions. - Remove Entity from infrastructure layer to better align with DDD (domain-driven design) as it's a domain concern. - Remove EntityBase for simplicity and to avoid technical nomenclature in names. - Introduce new types for keys and identifiable objects. - Create subfolders in `src/domain` for better structure/navigatability. - Improve context on thrown error messages. - Use string IDs for categories instead of using numeric pseudo-IDs. - Add more test cases for new functionality and extend existing tests to ensure no functionality is broken.
- Loading branch information
1 parent
22d6c79
commit fc9b282
Showing
141 changed files
with
3,225 additions
and
1,105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
""" | ||
Description: | ||
This script checks the existing collection files and add `id` field to missing script/categories | ||
by generating a new unique id. | ||
Usage: | ||
python3 ./scripts/add_missing_ids.py | ||
Note: | ||
This command must run from the project root directory. | ||
""" | ||
# pylint: disable=missing-function-docstring,missing-class-docstring | ||
|
||
import os | ||
from pathlib import Path | ||
import re | ||
import sys | ||
from typing import List, Set | ||
import uuid | ||
|
||
def main() -> None: | ||
collections_directory = './src/application/collections' | ||
yaml_file_paths = find_yaml_files(collections_directory) | ||
if not yaml_file_paths: | ||
print('No collection files found', file=sys.stderr) | ||
sys.exit(1) | ||
print(f'Total collection files found: {len(yaml_file_paths)}.') | ||
|
||
for yaml_file_path in yaml_file_paths: | ||
print(f'Processing: {yaml_file_path}') | ||
old_contents = read_yaml_file(yaml_file_path) | ||
processed_yaml = add_id_to_yaml_content(old_contents) | ||
if not processed_yaml.total_new_ids: | ||
print('👌 No changes needed, no missing IDs.') | ||
continue | ||
save_yaml_file(yaml_file_path, processed_yaml.new_content) | ||
print(f'🆕 Added missing IDs (total: {processed_yaml.total_new_ids}).') | ||
|
||
class YamlIdAdditionResult: | ||
def __init__(self, new_content: str, total_new_ids: int): | ||
self.new_content = new_content | ||
self.total_new_ids = total_new_ids | ||
|
||
def add_id_to_yaml_content(content: str) -> YamlIdAdditionResult: | ||
# Avoiding external yaml libraries to preserve YAML structure and comments. | ||
existing_ids = find_existing_ids(content) | ||
original_lines = content.splitlines() | ||
new_lines = [] | ||
total_new_ids = 0 | ||
functions_section_reached = False | ||
for i, line in enumerate(original_lines): | ||
if is_functions_section_start(line): | ||
functions_section_reached = True | ||
if (not functions_section_reached) and \ | ||
is_executable_name(line) and \ | ||
(not has_line_before_defined_id(i, original_lines)): | ||
indentation = len(line) - len(line.lstrip()) | ||
new_id = generate_unique_id(existing_ids) | ||
total_new_ids += 1 | ||
existing_ids.add(new_id) | ||
id_line_prefix = "#" if is_preceding_line_comment(i, original_lines) else "" | ||
id_line = f'{" " * indentation}{id_line_prefix}id: {new_id}' | ||
new_lines.append(id_line) # Insert new id line before 'name:' | ||
new_lines.append(line) | ||
return YamlIdAdditionResult( | ||
new_content=os.linesep.join(new_lines), | ||
total_new_ids=total_new_ids, | ||
) | ||
|
||
def is_functions_section_start(collection_file_line: str) -> bool: | ||
return 'functions:' in collection_file_line | ||
|
||
def is_executable_name(collection_file_line: str) -> bool: | ||
non_commented_line = get_non_commented_line(collection_file_line) | ||
stripped_line = non_commented_line.lstrip() | ||
return stripped_line.startswith('name:') or stripped_line.startswith('category:') | ||
|
||
def is_preceding_line_comment(current_line: int, all_lines: list[str]) -> bool: | ||
return current_line > 0 and all_lines[current_line-1].strip().startswith('#') | ||
|
||
def has_line_before_defined_id(current_line: int, all_lines: list[str]) -> bool: | ||
if current_line == 0: | ||
return False | ||
line_before = all_lines[current_line-1] | ||
non_commented_line = get_non_commented_line(line_before) | ||
stripped_line = non_commented_line.lstrip() | ||
return stripped_line.startswith('id:') | ||
|
||
def save_yaml_file(absolute_file_path: str, new_contents: str) -> None: | ||
with open(absolute_file_path, 'w', encoding='utf-8') as file: | ||
file.write(new_contents) | ||
|
||
def read_yaml_file(absolute_file_path: str) -> str: | ||
with open(absolute_file_path, 'r', encoding='utf-8') as file: | ||
return file.read() | ||
|
||
def find_yaml_files(directory_path: str) -> List[str]: | ||
return list(Path(directory_path).glob('**/*.yaml')) | ||
|
||
def find_existing_ids(content: str) -> Set[str]: | ||
pattern = r'^\s*#?\s*id:\s*(\S+)' # Matches 'id:' lines including commented lines | ||
return set(re.findall(pattern, content, re.MULTILINE)) | ||
|
||
def get_non_commented_line(yaml_line: str) -> str: | ||
pattern = re.compile(r'^\s*#\s?(.*)$') | ||
match = pattern.match(yaml_line) | ||
return match.group(1) if match else yaml_line | ||
|
||
def generate_unique_id(generated_ids: Set[str]) -> str: | ||
new_id = generate_new_id() | ||
while new_id in generated_ids: | ||
new_id = generate_new_id() | ||
return new_id | ||
|
||
def generate_new_id() -> str: | ||
partial_uuid = str(uuid.uuid4()).split('-', maxsplit=1)[0] | ||
if is_numeric(partial_uuid): # Creates issues with yaml parsing, yaml considering it as a number | ||
return generate_new_id() | ||
return partial_uuid | ||
|
||
def is_numeric(string: str) -> bool: | ||
numeric_pattern = re.compile(r'^\d+$|^[+-]?\d+\.?\d*[eE][+-]?\d+$') | ||
return numeric_pattern.match(string) | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 5 additions & 5 deletions
10
src/application/Context/State/Code/Event/ICodeChangedEvent.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,11 @@ | ||
import type { IScript } from '@/domain/IScript'; | ||
import type { Script } from '@/domain/Executables/Script/Script'; | ||
import type { ICodePosition } from '@/application/Context/State/Code/Position/ICodePosition'; | ||
|
||
export interface ICodeChangedEvent { | ||
readonly code: string; | ||
readonly addedScripts: ReadonlyArray<IScript>; | ||
readonly removedScripts: ReadonlyArray<IScript>; | ||
readonly changedScripts: ReadonlyArray<IScript>; | ||
readonly addedScripts: ReadonlyArray<Script>; | ||
readonly removedScripts: ReadonlyArray<Script>; | ||
readonly changedScripts: ReadonlyArray<Script>; | ||
isEmpty(): boolean; | ||
getScriptPositionInCode(script: IScript): ICodePosition; | ||
getScriptPositionInCode(script: Script): ICodePosition; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 4 additions & 4 deletions
8
src/application/Context/State/Filter/Result/AppliedFilterResult.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,9 @@ | ||
import type { IScript, ICategory } from '@/domain/ICategory'; | ||
import type { Category } from '@/domain/Executables/Category/Category'; | ||
import type { Script } from '@/domain/Executables/Script/Script'; | ||
|
||
export interface FilterResult { | ||
readonly categoryMatches: ReadonlyArray<ICategory>; | ||
readonly scriptMatches: ReadonlyArray<IScript>; | ||
readonly categoryMatches: ReadonlyArray<Category>; | ||
readonly scriptMatches: ReadonlyArray<Script>; | ||
readonly query: string; | ||
hasAnyMatches(): boolean; | ||
} |
4 changes: 2 additions & 2 deletions
4
src/application/Context/State/Filter/Strategy/FilterStrategy.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
import type { ICategoryCollection } from '@/domain/ICategoryCollection'; | ||
import type { CategoryCollection } from '@/domain/Collection/CategoryCollection'; | ||
import type { FilterResult } from '../Result/FilterResult'; | ||
|
||
export interface FilterStrategy { | ||
applyFilter( | ||
filter: string, | ||
collection: ICategoryCollection, | ||
collection: CategoryCollection, | ||
): FilterResult; | ||
} |
Oops, something went wrong.