Skip to content

Commit f7c5be7

Browse files
committed
fix(markdown_to_bbcode): improve URL generation for links
function convert_markdown_to_bbcode(markdown_text): ~refactor absolute URL construction for GitHub links function get_repo_name(): ~enhance repo name extraction with regex for better compatibility
1 parent a177c87 commit f7c5be7

File tree

2 files changed

+231
-6
lines changed

2 files changed

+231
-6
lines changed
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
# Commit Message Guide (Concise)
2+
3+
Conventional Commits + release-please. Multi-entry (multiple headers in one commit) is MANDATORY whenever a commit affects more than one substantive component (class, module, folder, feature). One header per component.
4+
5+
## 1. Header
6+
7+
Format: `type(scope): summary`
8+
9+
Types: feat | fix | perf | refactor | docs | test | build | ci | chore | style | deps
10+
11+
Scope: EXACT component identifier (file/class/module/folder keyword): e.g. `scriptProperties`, `scriptCompletion`, `languageFiles`, `extension`, `lua`, `build`. Do NOT use umbrella scopes (e.g. `scripts`) or comma scopes. If multiple components change, add additional headers (multi-entry) instead of broadening scope.
12+
13+
Summary: imperative, <=72 chars, no period, describes intent + effect.
14+
15+
## 2. Body
16+
17+
Blank line after header. Optional. With two space indentation per line. One line per significant file or class:
18+
19+
```text
20+
src/path/file.ts: what changed (why/impact)
21+
Class Name: what changed (why)
22+
```
23+
24+
User-facing first, internal later. Trivial style-only edits: separate `style:` commit or prefix line with `style:`.
25+
26+
### 2.1 Granular Change Points (MANDATORY DETAIL LEVEL)
27+
28+
Body lines MUST reference the most specific changed program element(s) when substantive (logic / API / behavior). Use one line per element category when clarity improves scanability. Prefer stable identifiers.
29+
30+
Allowed granular targets (in order of preference):
31+
32+
* File path (broad grouping)
33+
* Class \<Name\>
34+
* Class \<Name\>#methodName(params)
35+
* function functionName(params)
36+
* interface \<Name\> / type \<Name\>
37+
* enum \<Name\> / enum \<Name\>.\<Member\>
38+
* variable/const \<NAME\> (top-level exported) or prop \<Class\>.\<prop\>
39+
40+
Recommended notation tokens (prefix at start of description segment, optional but encouraged):
41+
42+
* `+` added
43+
* `-` removed
44+
* `~` modified (non-breaking)
45+
* `!` breaking change (also still add BREAKING CHANGE footer if external)
46+
* `` refactored equivalent behavior
47+
* `Δ` performance-impacting modification
48+
49+
Format patterns:
50+
51+
```text
52+
Class ScriptProperties#initialize(): +async init path (non-blocking startup)
53+
function parseLanguageFile(path): ~stream parsing (reduce memory)
54+
src/scripts/scriptCompletion.ts: Δ loop optimization (avoid quadratic filtering)
55+
Class CompletionProvider#provideCompletionItems(): ! signature drop 'token' param (internal) (see below)
56+
const MAX_KEYWORDS: -removed (unused)
57+
prop ScriptProperties.cache: +added (memoize keyword lookups)
58+
interface KeywordEntry: ~add optional 'category'
59+
```
60+
61+
If multiple tiny related changes occur inside one class, aggregate under the class line and enumerate methods inline separated by semicolons:
62+
63+
```text
64+
Class LanguageFiles: ~load(); +indexLanguages(); ~parseFile(): streaming SAX
65+
```
66+
67+
Signature changes should specify old → new when not obvious:
68+
69+
```text
70+
Class ScriptProperties#processKeywords(files[]): signature files[] -> sources[] (generalized input)
71+
```
72+
73+
Variable lines only for additions/removals/renames of exported or widely used constants / config toggles. Skip local implementation detail variables.
74+
75+
Avoid vague descriptions; specify what changed AND the direct impact (latency, memory, correctness, API surface, safety, etc.).
76+
77+
When a line uses `!` include a concise migration note either in parentheses or in the BREAKING footer.
78+
79+
## 3. Footers
80+
81+
Use only as needed (with the same indentation rules as for the bodies):
82+
83+
* BREAKING CHANGE: impact + migration
84+
* Closes #123 / Refs #456
85+
* deps: bump \<pkg\> from \<old\> to \<new\>
86+
* (Security) still use fix:; add CVE if any
87+
88+
## 4. Breaking Changes
89+
90+
Only for externally observable or API behavior changes. Each breaking entry (primary or secondary) needs its own `BREAKING CHANGE:` footer placed directly under that entry.
91+
92+
## 5. Multi-Entry Commits (Mandatory for Multi-Component Changes)
93+
94+
Required whenever the diff includes more than one substantive component. Each component gets its own header block. Prefer separate physical commits only if they can stand independently AND keep history bisectable; otherwise multi-entry.
95+
96+
Structure (repeat header/body/footers per component):
97+
98+
```text
99+
<primary header>
100+
101+
<primary body>
102+
<primary footers>
103+
104+
<secondary header>
105+
<secondary body (optional)>
106+
<secondary footers (optional)>
107+
108+
<tertiary header> ... etc
109+
```
110+
111+
Rules:
112+
113+
1. Additional headers start at column 1 after a blank line.
114+
2. Exactly one component per header (no umbrella or multi-component scopes).
115+
3. Body lines under a header list ONLY that component's files/classes.
116+
4. Footers apply only to the immediately preceding header block.
117+
5. Breaking for multiple components? Duplicate appropriately tailored `BREAKING CHANGE:` footers under each affected header (avoid vague shared footer).
118+
6. Nothing after the final entry's footers.
119+
7. Do NOT fabricate extra headers for trivial style noise—exclude or separate into its own commit.
120+
121+
Example (three components changed):
122+
123+
```text
124+
feat: add v4 UUID support
125+
126+
Implements UUID v4 generation for scripts.
127+
128+
fix(utils): unicode encode no longer throws
129+
BREAKING CHANGE: encode() now returns fallback string instead of throwing.
130+
131+
feat(utils): add unicode-capable encode variant
132+
```
133+
134+
### Indentation Rules (Multi-Entry Metadata)
135+
136+
When including metadata/footer lines (e.g. `PiperOrigin-RevId:`, `Source-Link:`, internal IDs) for secondary or tertiary headers you MAY indent them by two spaces for readability. Indentation is optional; consistency within a commit is preferred. The `BREAKING CHANGE:` footer line itself should NOT be indented (to ensure parsers pick it up cleanly).
137+
138+
Indented example with metadata:
139+
140+
```text
141+
feat: adds v4 UUID to crypto
142+
143+
This adds support for v4 UUIDs to the library.
144+
145+
fix(utils): unicode no longer throws exception
146+
PiperOrigin-RevId: 345559154
147+
BREAKING CHANGE: encode method no longer throws.
148+
Source-Link: googleapis/googleapis@5e0dcb2
149+
150+
feat(utils): update encode to support unicode
151+
PiperOrigin-RevId: 345559182
152+
Source-Link: googleapis/googleapis@e5eef86
153+
```
154+
155+
Parsing expectations:
156+
157+
* Each unindented `type(scope?): summary` line starts a new entry.
158+
* Indented lines (2 leading spaces) immediately following a header or its body belong to that entry's body/footers.
159+
* A blank line separates entries.
160+
* `BREAKING CHANGE:` (indented or not) is associated with the closest preceding header without an intervening new header line.
161+
162+
## 6. Examples
163+
164+
Feature + perf:
165+
166+
```text
167+
feat(languageFiles): async load with concurrency
168+
169+
Class LanguageFiles#loadAll(): ~async refactor (prevent extension host blocking)
170+
function parseLanguageFile(path): +concurrency limit (8 workers)
171+
172+
feat(scriptProperties): async initialization
173+
174+
Class ScriptProperties#initialize(): +async; -sync path (non-blocking startup)
175+
prop ScriptProperties.cache: +added memoization (reduces repeat parsing)
176+
177+
refactor(extension): await readiness of scriptProperties & languageFiles
178+
179+
src/extension.ts: ~activation flow (providers registered after data ready)
180+
```
181+
182+
Bug fix:
183+
184+
```text
185+
fix(completion): suppress suggestions inside single-quoted attribute values
186+
187+
function isInsideSingleQuotedString(text,pos): +added (central quote detection)
188+
Class CompletionProvider#provideCompletionItems(): ~early return when inside single-quoted value (reduces noise)
189+
```
190+
191+
Breaking refactor:
192+
193+
```text
194+
refactor(api): remove deprecated synchronous init path
195+
196+
src/init/legacyInit.ts: -removed (obsolete)
197+
Class ExtensionActivator#activate(): ~drop legacyInit(); ~await ScriptProperties.initialize()
198+
BREAKING CHANGE: callers must await initialize() before provider use (sync path removed).
199+
```
200+
201+
## 7. Checklist (Pre-Commit)
202+
203+
1. Every substantive component changed has its own header (no umbrella / multi scopes).
204+
2. Each header: valid type + precise component scope + imperative summary (<=72 chars, no period).
205+
3. Bodies: per-header; only files/classes of that component; concise what + why.
206+
4. Breaking changes duplicated under each affected component's header (if applicable).
207+
5. Footers (refs, deps) scoped to relevant header only.
208+
6. No vague verbs (avoid solitary "update", "improve").
209+
7. No build artifacts or timestamps.
210+
8. Regex validation passes for every header.
211+
9. Only substantive components get headers (don't add headers for trivial whitespace).
212+
213+
## 8. Validation Regex (Header)
214+
215+
```regex
216+
^(feat|fix|perf|refactor|docs|test|build|ci|chore|style|deps)(\([a-z0-9_.,-]+\))?: [A-Z0-9].{0,71}$
217+
```
218+
219+
Secondary headers in multi-entry commits must also match this pattern starting at column 1 after a blank line.
220+
221+
## 9. Multi-Entry Detection Heuristic
222+
223+
After the first block, treat any line matching the header regex (column 1, preceded by a blank line) as a new entry until EOF.
224+
225+
Adhere to these concise rules for consistent automated releases, readable history, and accurate changelogs.

markdown_to_bbcode.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import sys
44
import os
55
import subprocess
6+
from urllib.parse import urljoin
67

78
def convert_markdown_to_bbcode(markdown_text, repo_name=None, bbcode_type='egosoft', relative_path=None):
89
"""
@@ -194,6 +195,7 @@ def replace_links(match):
194195
return f"{link_text}\n[youtube]{video_id}[/youtube]"
195196
elif repo_name and not re.match(r'^https?://', link_url):
196197
absolute_url = f"https://github.com/{repo_name}/raw/main/{relative_path}/{link_url}"
198+
absolute_url = urljoin(urljoin(f"https://github.com/{repo_name}/raw/main/", relative_path.strip('/')), link_url.strip('/'))
197199
return f"[url={absolute_url}]{link_text}[/url]"
198200
else:
199201
return f"[url={link_url}]{link_text}[/url]"
@@ -277,12 +279,10 @@ def get_repo_name():
277279
"""
278280
try:
279281
repo_url = subprocess.check_output(['git', 'config', '--get', 'remote.origin.url'], encoding='utf-8').strip()
280-
if repo_url.startswith('https://github.com/'):
281-
repo_name = repo_url[len('https://github.com/'):]
282-
return repo_name.rstrip('.git')
283-
elif repo_url.startswith('[email protected]:'):
284-
repo_name = repo_url[len('[email protected]:'):]
285-
return repo_name.rstrip('.git')
282+
pattern = re.compile(r"([^/:]+)/([^/]+)\.git$")
283+
match = pattern.search(repo_url)
284+
if match:
285+
return f"{match.group(1)}/{match.group(2)}"
286286
else:
287287
print(f"Error: Unsupported repository URL format: {repo_url}")
288288
sys.exit(1)

0 commit comments

Comments
 (0)