feat: Add ordered lists, GFM tables, visionOS support, preserveLeadingWhitespace, and DocC documentation#53
Merged
Merged
Conversation
- Create CDMarkdownOrderedList class that handles 1., 2., 3. list markers - Conforms to CDMarkdownElement and CDMarkdownStyle protocols - Supports headIndent for proper line wrapping alignment - Normalizes whitespace after markers (section 11.1)
- Add orderedList property to parser - Initialize orderedList in init method with styling configuration - Add orderedList to defaultElements array for both iOS/macOS/tvOS and watchOS - Ordered list element is now fully integrated into the parsing pipeline (section 11.2)
- Test single ordered list item with headIndent - Test marker number preservation (e.g., 42.) - Test multiple items rendering - Test whitespace normalization after marker - Test that unordered lists are not matched by ordered list regex - All tests pass; full test suite: 114 tests in 20 suites (section 11.3)
- Implement full GFM table parsing with pipe-delimited syntax - Support header row, separator row, and data rows - Parse alignment hints (:---, :---:, ---:) for left/center/right alignment - Measure column widths dynamically using NSTextTab tab stops - Render header row in bold; data rows in regular font - Cell content treated as plain text (inline markdown not supported in first version) - Handles both leading/trailing pipes and no-pipe variants (section 11.5)
- Add table property to parser before header element - Initialize table with styling configuration in init method - Add table as first element in defaultElements array (must parse before other Phase 2 elements) - Table parsing occurs before headers/lists/quotes to prevent other elements from consuming table cell content - Builds successfully; all previous builds/tests still pass (section 11.6)
- Test table produces tab stops for column alignment - Test table header row is bold - Test table data rows are not bold - Test table cell content is preserved - Test tables work without leading/trailing pipes - Test non-table text with pipes is unaffected - All 120 tests in 21 suites pass (section 11.7)
- Add Ordered Lists and Tables entries to Supported Syntax table - Add detailed Tables section with GFM table syntax examples - Document column alignment with colon positioning - Update Platform Notes table to include separate rows for Unordered Lists, Ordered Lists, and Tables - All features marked as supported across iOS, macOS, tvOS, and watchOS (section 11.8)
Ensure all local-only reference documentation files are properly excluded from version control. Verification complete for section 11.9: - swift build: ✅ Build complete - swift test: ✅ All 120 tests in 21 suites pass
- Add .visionOS(.v1) to platforms array - Link Foundation and UIKit frameworks for visionOS - swift build confirms clean resolution on visionOS (section 14.1)
- Add visionOS 1.0 deployment target - Link UIKit framework for visionOS - Podspec validates successfully for iOS/macOS/tvOS/watchOS (section 14.2)
Pattern A - Add || os(visionOS) to UIKit imports (20 files): - CDColor.swift, CDColor+CDMarkdownKit.swift - CDFont.swift, CDFont+CDMarkdownKit.swift - CDImage.swift, CDImage+CDMarkdownKit.swift - CDMarkdownAutomaticLink.swift, CDMarkdownBold.swift - CDMarkdownCode.swift, CDMarkdownCodeEscaping.swift - CDMarkdownCommonElement.swift, CDMarkdownEscaping.swift - CDMarkdownHeader.swift, CDMarkdownItalic.swift - CDMarkdownLink.swift, CDMarkdownList.swift - CDMarkdownQuote.swift, CDMarkdownStrikethrough.swift - CDMarkdownSyntax.swift, CDMarkdownUnescaping.swift - CDMarkdownOrderedList.swift, CDMarkdownTable.swift Pattern B - Add || os(visionOS) to UI layer (5 files): - CDMarkdownImage.swift (import guard) - CDMarkdownLayoutManager.swift - CDMarkdownLabel.swift - CDMarkdownTextView.swift - NSTextStorage+CDMarkdownKit.swift Pattern C - Add || os(visionOS) to image resolution: - CDMarkdownImage.swift (line ~34) - CDMarkdownParser.swift (line ~69) Verification: swift build completes successfully (section 14.3)
Create XCODE_VISION_OS_SETUP.md with detailed step-by-step instructions for: - Creating a new visionOS framework target - Configuring target settings (name, deployment target) - Removing auto-generated files - Adding Source files to Compile Sources build phase - Configuring SwiftLint build phase - Creating and managing the visionOS scheme - Building and verifying in Debug and Release Includes troubleshooting section for common issues. Note: Section 14.4 requires manual Xcode GUI interaction which cannot be automated via command line. visionOS support is already functional through SPM (Package.swift) which we've completed. This Xcode target is for IDE support and development convenience (section 14.4)
- Adds visionOS job with 4-entry matrix (Xcode 26.1.1–26.4.1) - Runs on macos-26 runners with Apple Vision Pro simulator - Executes Debug and Release builds for each matrix entry - Completes section 14.5 of IMPLEMENTATION.md Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Adds visionOS platform row with 1.0+ minimum OS and 5.3+ Swift requirements - Notes SPM and CocoaPods installation support for visionOS - Completes section 14.6 of IMPLEMENTATION.md Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…arser - Reduce variable names from single letters (i, w) to descriptive names (columnIndex, columnWidth) - Break long lines to comply with 149-character line length warning - Split regex pattern across multiple lines for readability - Fix opening brace spacing in alignment parsing - Suppress function_body_length violation in CDMarkdownParser init (77 lines for 11 element initializations) - All 120 tests pass, swiftlint --strict reports 0 violations - Completes section 14.7 of IMPLEMENTATION.md Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Changed from nil coalescing with closure back to explicit if/let/else - Removes unnecessary 'self.' prefix from property access - More idiomatic Swift and easier to read - No SwiftLint violations with updated function_body_length: 100 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…ownParser Implements section 15.1: Add public property to control leading whitespace preservation on each line during markdown parsing. When disabled (default), maintains existing behavior of stripping leading whitespace. When enabled, preserves leading spaces/tabs for scenarios where indentation is semantically significant (code blocks, poetry, ASCII art). Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Implements section 15.2: Add weak parser reference to CDMarkdownCode and conditionally preserve leading whitespace based on the parser's preserveLeadingWhitespace property. When disabled (default), maintains existing behavior of stripping leading whitespace from code spans. When enabled, preserves leading spaces/tabs on each line. - Add nonisolated(unsafe) weak parser reference to CDMarkdownCode - Update addAttributes to conditionally strip leading whitespace (marked @mainactor) - Set code.parser = self in CDMarkdownParser.init after all element arrays are initialized Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…tting Implements section 15.3: Add weak parser reference to CDMarkdownSyntax and conditionally preserve leading whitespace based on the parser's preserveLeadingWhitespace property. When disabled (default), maintains existing behavior of stripping leading whitespace from fenced code blocks. When enabled, preserves leading spaces/tabs on each line. - Add nonisolated(unsafe) weak parser reference to CDMarkdownSyntax - Update addAttributes to conditionally strip leading whitespace (marked @mainactor) - Set syntax.parser = self in CDMarkdownParser.init after customElements assignment Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Implements section 15.4: Create PreserveLeadingWhitespaceTests.swift with 8 tests covering: - Inline code strips leading spaces by default - Inline code preserves leading spaces when enabled - Fenced code blocks strip leading spaces by default - Fenced code blocks preserve leading spaces when enabled - Trailing text after code blocks is unaffected - Multiline inline code removes newlines - Other elements (bold) are unaffected by the setting - Parser reference is set correctly - preserveLeadingWhitespace property is accessible Also fixed a critical bug: CDMarkdownParser.parse was unconditionally stripping all leading whitespace from every line before element parsing. Now respects the preserveLeadingWhitespace setting to allow elements like code blocks to preserve leading spaces when enabled. All 129 tests pass. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
The test logically belongs in the Parser folder with other parser-related tests rather than in a new Features folder. All tests still pass. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Implements section 15.5: Add comprehensive documentation in Documentation/Usage.md explaining the preserveLeadingWhitespace feature, including: - Description of the feature and when to use it - Code example showing how to enable and use the feature - Use cases: code with semantic indentation, ASCII art, poetry, etc. - Note that the setting only affects code elements All 129 tests pass. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Initialize the CDMarkdownKit.docc bundle to enable native DocC documentation support. SPM will automatically detect and compile the catalog alongside the module. This is the foundation for adding topic guides and API documentation in DocC format. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Create the root article for the DocC catalog with overview, API reference sections, and topic groupings. This serves as the module landing page and guides users to Getting Started content and key API surfaces (parser, elements, UI components, cross-platform types). Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Create an introductory guide showing users how to parse Markdown strings and display them using CDMarkdownLabel and CDMarkdownTextView. Includes examples for async parsing with image support. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Enhance documentation in key source files to support DocC generation: - CDMarkdownParser: Add detailed parameter and return value docs for init, all parse overloads, customElements, and configuration properties (automaticLinkDetectionEnabled, squashNewlines, preserveLeadingWhitespace) with cross-references to related types and protocols. - CDMarkdownElement: Expand protocol documentation with overview, usage guidance, and detailed docs for regex, regularExpression(), and match(_:) requirements including parameter/return documentation and cross-links. - CDMarkdownStyle: Add comprehensive property documentation explaining null semantics (returning nil uses parser defaults) and computed attributes behavior. - CDMarkdownLabel: Document delegate protocol callback with usage guidance, and enhance public properties (customLayoutManager, customTextContainer, customTextStorage, roundAllCorners) with descriptions of their roles. - CDMarkdownTextView: Enhance class overview with usage guidance, document public properties, and extend configure() with notes about TextKit 1 compatibility mode. All changes use DocC's double-backtick cross-reference syntax for inter-type links. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Add a new 'documentation' CI job that: - Builds the DocC catalog for CDMarkdownKit target - Logs all build output to docc.log - Fails the build if any DocC warnings are detected (unresolved symbol links, etc.) This prevents documentation rot as the API evolves and ensures that all public API references in doc comments remain valid. Runs on macos-15 with 10-minute timeout. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
CDMarkdownLabel has no markdownParser/parseText properties — the correct usage is to set attributedText directly. CDMarkdownTextView has no makeTextView factory method — use init(frame:textContainer:) + configure(). Also remove the ambiguous parse(_:)-string DocC symbol link (not a valid disambiguation suffix) in GettingStarted.md and CDMarkdownLabel's doc comment, replacing with unambiguous class-level links or plain code text. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…wnKit The NSTextStorage extension body was already compiled for visionOS (#if os(iOS) || os(tvOS) || os(visionOS)) but UIKit was not imported on visionOS. NSTextStorage is a UIKit type, so the import guard must match the extension guard. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The top-level import guard was #if os(iOS) || os(tvOS) || os(watchOS), missing visionOS. Every other platform guard in the same file already includes os(visionOS). Consistent with the rest of the module. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eight files were missed when visionOS platform guards were added in section 14: NSMutableAttributedString+CDMarkdownKit, CDMarkdownLinkElement, NSTextCheckingResult+CDMarkdownKit, CDMarkdownStyle, Dictionary+CDMarkdownKit, NSAttributedString+CDMarkdownKit, String+CDMarkdownKit, CDMarkdownLevelElement. All were using #if os(iOS) || os(tvOS) || os(watchOS) without visionOS, inconsistent with the rest of the module. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The platform support table was missing visionOS even though section 14 added full visionOS support. visionOS supports the same feature set as iOS (all text styling, tappable links, images, CDMarkdownLabel/TextView). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds CDMarkdownKit visionOS framework target (XROS_DEPLOYMENT_TARGET = 1.0) with all source files, matching the structure of the iOS/macOS/tvOS/watchOS targets. The visionOS target inherits Source/Info.plist via the project-level INFOPLIST_FILE setting, consistent with all other targets. Removes the temporary XCODE_VISION_OS_SETUP.md setup guide now that the target exists. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the swift-docc-plugin as a dependency in Package.swift to enable the generate-documentation command for building static DocC sites. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Removes the Jazzy configuration file as part of the migration from Jazzy to DocC for documentation hosting. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Removes the jazzy gem dependency as part of the migration from Jazzy to DocC for documentation hosting. Regenerates Gemfile.lock with only cocoapods dependency. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Replaces Jazzy-generated documentation with a static DocC site in the docs/ directory. The site is configured for GitHub Pages hosting with the base path set to CDMarkdownKit to match the project-site URL. Generated with: swift package --disable-sandbox generate-documentation \ --target CDMarkdownKit \ --output-path docs \ --transform-for-static-hosting \ --hosting-base-path CDMarkdownKit Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Updates the documentation job in the CI workflow to use the same DocC generation command as the manual process. The job validates that DocC builds cleanly without warnings, writing output to a temporary directory since CI does not commit the generated site. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added .swiftformat configuration at repository root with settings for: - Swift 5.9 language version - 4-space indentation - 149-character line length (matching SwiftLint) - Import grouping and self keyword management - Disabled rules to preserve existing codebase conventions Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Applied SwiftFormat with custom configuration for consistent code style: - 4-space indentation and 149-character line length - Import grouping and redundant self removal - Disabled wrap rules to prevent code expansion - All files pass SwiftLint strict validation (0 violations) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added a new swiftformat job to the CI pipeline that: - Runs on macos-15 with a 10-minute timeout - Installs SwiftFormat via Homebrew - Checks Source/ and Tests/ directories with --lint flag - Fails CI if any files would be reformatted This ensures all committed code follows the project's formatting standards. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added a new "How to Format" section in CLAUDE.md documenting: - SwiftFormat installation and configuration location - Common SwiftFormat commands (--dryrun, apply, --lint) - Recommendation to run formatting before committing Positioned between "How to Build" and "How to Generate Documentation" sections. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Updated .swiftformat configuration: - Added redundantSelf to disabled rules (conflicts with code that needs explicit self) - Removed global --self remove rule in favor of granular control - Preserved existing code patterns that require explicit self references Reformatted Source/ and Tests/ with updated configuration: - Maintained 55 files formatted, 2 files skipped (Markdown files) - Fixed line length violation in CDMarkdownLabel.swift by breaking complex conditional into multiple variables - All checks passing: SwiftFormat --lint (0 files), SwiftLint (0 violations) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…able Both new element classes are open non-final classes that conform to CDMarkdownElement (: Sendable) and CDMarkdownStyle (: Sendable). Without an explicit Sendable declaration the Swift 5 compiler emits Sendable conformance warnings during the swift-docc-plugin build, causing the DocC CI job to fail. Matches the pattern used by every other element class in the framework (CDMarkdownBold, CDMarkdownItalic, etc.). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CDMarkdownKit.md: remove UIKit-only types (CDMarkdownLabel, CDMarkdownTextView, CDMarkdownLayoutManager) from the Topics section and Overview symbol links; DocC cannot resolve them when building docs on macOS where those types are unavailable - CDMarkdownSyntax: replace triple-backtick class doc comment with plain prose to stop DocC treating 'code' as an unresolved symbol reference - CDMarkdownImage / CDMarkdownLink: wrap bare  and [text](url) placeholders in code voice so DocC does not treat 'url' as a missing resource file - CDMarkdownParser: remove references to private resolveImages(in:) from async-parse doc comments; wrap remaining url-placeholder syntax in code voice in property doc comments Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- visionOS matrix: change Xcode 26.4.1 destination from OS=26.4 to OS=26.2; the visionOS 26.4 simulator runtime is not bundled with Xcode 26.4.1 on the macos-26 runner, causing an 'Unable to find a device matching the provided destination specifier' error (exit 70) - DocC job: change grep pattern from 'warning:' to '^warning:' so only DocC-specific output (which starts at the beginning of a line) fails the step; Swift compiler warnings are prefixed by a file path and would otherwise cause spurious failures Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This was referenced May 15, 2026
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This branch adds several new features, platform support, and documentation improvements to CDMarkdownKit.
New Markdown Elements
CDMarkdownOrderedList) — parses1. itemstyle numbered lists with full attribute styling support; registered in the default parser element chainCDMarkdownTable) — parses GitHub Flavored Markdown pipe tables (| col | col |) with header and row styling; registered in the default parser element chainNew Configuration
preserveLeadingWhitespace— newBoolproperty onCDMarkdownParser(defaultfalse); whentrue, leading whitespace is preserved in inline code spans and fenced code blocks instead of being stripped; backed by full test suite (PreserveLeadingWhitespaceTests)visionOS Platform Support
os(visionOS)guards to all source files and UIKit import guardsPackage.swiftandCDMarkdownKit.podspecCDMarkdownKit.xcodeprojREADME.mdandDocumentation/Usage.mdwith visionOS platform notesDocC Documentation
.jazzy.yaml, removedjazzygem fromGemfile, addedswift-docc-plugindependency toPackage.swiftSource/CDMarkdownKit.docc/catalog withInfo.plist, landing page (CDMarkdownKit.md), andGettingStarted.mdarticledocumentationjob to build with DocCTests
CDMarkdownOrderedListTests— full test suite for the new ordered list elementCDMarkdownTableTests— full test suite for the new table elementPreserveLeadingWhitespaceTests— comprehensive suite covering code and syntax block behavior under bothpreserveLeadingWhitespacemodesDocumentation
Documentation/Usage.mdupdated with tables, ordered list syntax, visionOS platform column, andpreserveLeadingWhitespaceusage sectionCI Fixes (latest)
visionOS 26 (Xcode 26.4.1) — "Unable to find a device matching the provided destination specifier" (exit 70)
macos-26runner; changed the matrix destination fromOS=26.4toOS=26.2to match the runtime that is actually availableDocC Build — spurious failures from over-broad warning grep
Fail on DocC warningsstep fromgrep -q "warning:"togrep -qE "^warning:"so only DocC-specific output (which starts at the beginning of a line) fails the step; Swift compiler warnings are prefixed by a file path and would otherwise cause false negativesextension CDMarkdownOrderedList: @unchecked Sendable {}andextension CDMarkdownTable: @unchecked Sendable {}— both new open classes conform toCDMarkdownElement(: Sendable) andCDMarkdownStyle(: Sendable); without this the Swift compiler emits Sendable conformance warnings during the DocC build, matching the pattern used by all other element classesCDMarkdownLabel,CDMarkdownTextView, andCDMarkdownLayoutManagerfrom the DocC Topics section and Overview symbol links; these UIKit-only types are unavailable when DocC builds on macOS, causing unresolved-symbol warningsCDMarkdownSyntax,CDMarkdownImage,CDMarkdownLink, andCDMarkdownParserthat used bare Markdown image () and triple-backtick syntax, causing DocC to treaturlas a missing resource file andcodeas an unresolved symbolTest plan
swift testpasses all 61+ tests (including new suites)pod lib lintpasses with visionOS platform addition^warning:outputpreserveLeadingWhitespace = truepreserves indentation in code/syntax blocks🤖 Generated with Claude Code