Skip to content

Commit f652d0f

Browse files
committed
tool: compiling specifications follows the extend attr for sub application types
1 parent 88887b6 commit f652d0f

File tree

2 files changed

+105
-3
lines changed

2 files changed

+105
-3
lines changed

bin/applications.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
def get_application_module_refs(application: object | str, specification: dict) -> list:
2+
"""
3+
Given an application object (or application ref string) and the full specification,
4+
return a deduplicated, alphabetical list of module reference strings.
5+
6+
- Accepts either the application dict or the application reference (string).
7+
- Handles modules listed as either strings or dicts with a "module" key.
8+
- If the application has an 'extends' attribute (string or list), modules from
9+
parent application(s) are included.
10+
- Prevents infinite loops in extends chains by tracking visited application refs.
11+
"""
12+
applications = specification.get("application", {}) or {}
13+
collected = set()
14+
visited_apps = set()
15+
16+
# normalize input: application may be a ref (str) or the application dict itself
17+
if isinstance(application, str):
18+
app_obj = applications.get(application)
19+
if not app_obj:
20+
return []
21+
elif hasattr(application, "get") and callable(getattr(application, "get")):
22+
# Accept frontmatter.Post which expose a `.get()` method. and dicts
23+
app_obj = application
24+
else:
25+
return []
26+
27+
def extract_module_ref(entry):
28+
"""Return a module ref string from an entry, or None.
29+
30+
Entry may be:
31+
- a string 'module-ref'
32+
- a dict {'module': 'module-ref'}
33+
- nested dicts where the value of 'module' is a dict (rare)
34+
"""
35+
if isinstance(entry, str):
36+
return entry
37+
if isinstance(entry, dict):
38+
# prefer explicit 'module' key
39+
if "module" in entry:
40+
val = entry["module"]
41+
# recurse if nested
42+
return extract_module_ref(val)
43+
# fallback: if dict has a single string value
44+
for v in entry.values():
45+
ref = extract_module_ref(v)
46+
if ref:
47+
return ref
48+
return None
49+
50+
def collect_from_app(app_obj):
51+
# collect modules from this app object; support 'modules' or singular 'module'
52+
mods = app_obj.get("modules", None)
53+
if mods is None:
54+
mods = app_obj.get("module", [])
55+
# if mods is a dict, iterate its values
56+
if isinstance(mods, dict):
57+
mods_iter = list(mods.values())
58+
else:
59+
mods_iter = mods or []
60+
61+
for m in mods_iter:
62+
mod_ref = extract_module_ref(m)
63+
if isinstance(mod_ref, str) and mod_ref:
64+
collected.add(mod_ref)
65+
66+
# follow extends if present
67+
extends = app_obj.get("extends")
68+
if not extends:
69+
return
70+
71+
parent_refs = extends if isinstance(extends, list) else [extends]
72+
for pref in parent_refs:
73+
if not isinstance(pref, str) or not pref:
74+
continue
75+
if pref in visited_apps:
76+
continue
77+
visited_apps.add(pref)
78+
parent_app = applications.get(pref)
79+
if parent_app:
80+
collect_from_app(parent_app)
81+
82+
# start collection from the resolved app_obj
83+
collect_from_app(app_obj)
84+
return sorted(collected)
85+
86+
87+
if __name__ == "__main__":
88+
print("Testing information model generation script.")
89+
90+
try:
91+
from loader import load_content
92+
93+
specification = load_content()
94+
print("Specification loaded successfully")
95+
96+
result = get_application_module_refs(
97+
specification["application"]["ldc-prospective-use"], specification
98+
)
99+
print(result)
100+
101+
except Exception as e:
102+
print(f"✗ Error: {e}")

bin/generate_info_model.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from applications import get_application_module_refs
12
from fields import (
23
format_field_display_name,
34
get_applicable_app_types,
@@ -175,9 +176,8 @@ def generate_application(app_ref, specification):
175176
# 2. Contents
176177
out.append("## Contents\n")
177178
out.append("* [Application data specification](#application-data-specification)")
178-
module_refs = [
179-
m["module"] if isinstance(m, dict) else m for m in app.get("modules", [])
180-
]
179+
# get full list of applicable modules
180+
module_refs = get_application_module_refs(app, specification)
181181
out.append("")
182182

183183
# 3. Modules List (contents)

0 commit comments

Comments
 (0)