diff --git a/.cursor/rules/README.md b/.cursor/rules/README.md new file mode 100644 index 0000000..0c75565 --- /dev/null +++ b/.cursor/rules/README.md @@ -0,0 +1,5 @@ +# Cursor (optional) + +**Cursor** users: start at the repo root **[`AGENTS.md`](../../AGENTS.md)**. All conventions live in **`skills/*/SKILL.md`** (universal for any editor or tool). + +This folder only points contributors here so nothing editor-specific duplicates the canonical docs. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e172364 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,53 @@ +# Contentstack Utils Swift – Agent guide + +**Universal entry point** for anyone automating or assisting work in this repo—AI agents (Cursor, Copilot, CLI tools), reviewers, and contributors. Conventions and detailed guidance live in **`skills/*/SKILL.md`**, not in editor-specific config, so the same instructions apply whether or not you use Cursor. + +## What this repo is + +- **Name:** [contentstack-utils-swift](https://github.com/contentstack/contentstack-utils-swift) +- **Purpose:** Swift library that renders Contentstack **RTE** (rich text) and related JSON to HTML, with hooks for embedded entries/assets and helpers for **variant** metadata. +- **Out of scope:** This package does **not** ship HTTP clients or stack credentials. Apps fetch content with the [Content Delivery / Swift SDK](https://www.contentstack.com/docs/developers/sdks/content-delivery-sdk/swift) (or other clients), then pass strings or dictionaries into ContentstackUtils. + +## Tech stack (at a glance) + +| Area | Details | +|------|---------| +| Language | Swift 5 (`Package.swift`, podspec) | +| Build | SwiftPM; CocoaPods `ContentstackUtils.podspec`; Xcode `ContentstackUtils.xcodeproj` | +| Tests | XCTest → `Tests/ContentstackUtilsTests/` | +| Lint / coverage | SwiftLint `.swiftlint.yml`; Slather `.slather.yml` (scheme `ContentstackUtils-Package`) | +| HTML/XML | Vendored Kanna `Sources/Kanna/`; libxml2 via `Modules/` | + +## Commands (quick reference) + +```bash +swift build && swift test +swiftlint +``` + +CI-style Xcode (see `.github/workflows/ci.yml`): + +```bash +xcodebuild -project "ContentstackUtils.xcodeproj" -scheme "ContentstackUtils-Package" -destination "OS=13.4.1,name=iPhone 11 Pro" test +``` + +CocoaPods: `pod 'ContentstackUtils', '~> …'` — see `README.md` and `ContentstackUtils.podspec` for the current version. + +## Where the real documentation lives: skills + +Read these **`SKILL.md` files** for full conventions—**this is the source of truth** for implementation and review: + +| Skill | Path | What it covers | +|-------|------|----------------| +| **Development workflow** | [`skills/dev-workflow/SKILL.md`](skills/dev-workflow/SKILL.md) | Branches, CI, build/test/lint commands, PR expectations, TDD note, Slather | +| **Contentstack Utils (SDK)** | [`skills/contentstack-utils/SKILL.md`](skills/contentstack-utils/SKILL.md) | Public API: `ContentstackUtils`, `Option` / `Renderable`, RTE/JSON, GQL, variants, errors, semver, no network layer | +| **Swift style & repo layout** | [`skills/swift-style/SKILL.md`](skills/swift-style/SKILL.md) | SwiftLint, `Sources/` layout, Kanna/libxml2, platforms, naming, access control | +| **Testing** | [`skills/testing/SKILL.md`](skills/testing/SKILL.md) | XCTest layout, mocks, fixtures, SwiftLint/Slather, offline tests, `XCTestManifests` | +| **Code review** | [`skills/code-review/SKILL.md`](skills/code-review/SKILL.md) | PR checklist (API, errors, deps/SCA, tests, vendored code), Blocker/Major/Minor | +| **Framework / build** | [`skills/framework/SKILL.md`](skills/framework/SKILL.md) | SPM targets, `Modules/` libxml2, Kanna vendoring, deployment targets, podspec, CI `xcodebuild` | + +An index with short “when to use” hints is in [`skills/README.md`](skills/README.md). + +## Using Cursor + +If you use **Cursor**, [`.cursor/rules/README.md`](.cursor/rules/README.md) only points to **`AGENTS.md`**—same source of truth as everyone else; no separate `.mdc` rule files. diff --git a/skills/README.md b/skills/README.md new file mode 100644 index 0000000..fc46249 --- /dev/null +++ b/skills/README.md @@ -0,0 +1,19 @@ +# Skills – Contentstack Utils Swift + +**This directory is the source of truth** for conventions (workflow, SDK API, style, tests, review, build). Read **`AGENTS.md`** at the repo root for the index and quick commands; each skill is a folder with **`SKILL.md`** (YAML frontmatter: `name`, `description`). + +## When to use which skill + +| Skill folder | Use when | +|--------------|----------| +| **dev-workflow** | Branches, CI, `swift build` / `swift test` / `swiftlint`, `xcodebuild`, PRs, Slather, optional TDD | +| **contentstack-utils** | `ContentstackUtils`, `Option` / `Renderable`, RTE/JSON, GQL, variants, errors, semver, docs | +| **swift-style** | SwiftLint, `Sources/` vs Kanna, libxml2/platforms, naming, access control | +| **testing** | XCTest layout, mocks, fixtures, offline tests, `XCTestManifests` | +| **code-review** | PR checklist, Blocker/Major/Minor, API and security gates | +| **framework** | `Package.swift`, `Modules/`, Kanna vendoring, podspec, CI scheme | + +## How to use these docs + +- **Humans / any AI tool:** Start at **`AGENTS.md`**, then open the relevant **`skills//SKILL.md`**. +- **Cursor users:** **`.cursor/rules/README.md`** only points to **`AGENTS.md`** so guidance stays universal—no duplicate `.mdc` rule sets. diff --git a/skills/code-review/SKILL.md b/skills/code-review/SKILL.md new file mode 100644 index 0000000..81b1619 --- /dev/null +++ b/skills/code-review/SKILL.md @@ -0,0 +1,60 @@ +--- +name: code-review +description: PR checklist—API stability, docs, errors, compatibility, dependencies/SCA, tests, vendored code; Blocker/Major/Minor. +--- + +# Code review – Contentstack Utils Swift + +## When to use + +- Reviewing a PR, self-review before submit, or automated review prompts. + +## Instructions + +Work through the checklist below. Optionally tag findings: **Blocker**, **Major**, **Minor**. + +### API design and stability + +- [ ] **Public API:** New or changed `public` / `open` types in `Sources/ContentstackUtils/` are necessary, semver-conscious, and documented (`README.md` / `CHANGELOG.md` when user-visible). +- [ ] **Backward compatibility:** No breaking changes unless explicitly justified (e.g. major version). Prefer additive behavior and default `Option()` paths. +- [ ] **Naming:** Matches existing Utils and RTE terminology (`ContentstackUtils`, `Option`, `Node`, `GQL`, etc.). + +### Error handling and robustness + +- [ ] **Errors:** New `throws` paths use clear domain types (e.g. `VariantUtilityError`); callers can distinguish invalid input from parsing failures where relevant. +- [ ] **Optionals:** No force-unwraps on public code paths; document preconditions for non-optional parameters. +- [ ] **RTE JSON:** Decoding and HTML traversal stay tolerant of documented stack payload shapes; embedded-item regressions are called out. + +### Dependencies and security + +- [ ] **Dependencies:** `Package.swift` / `ContentstackUtils.podspec` changes are justified; versions do not introduce known vulnerabilities. +- [ ] **SCA:** Address security findings (e.g. Snyk, org scanners) in the PR or via an agreed follow-up. + +### Testing + +- [ ] **Coverage:** New or modified behavior in `Sources/ContentstackUtils/` has tests under `Tests/ContentstackUtilsTests/` when feasible. +- [ ] **Quality:** Tests are readable, deterministic, and follow naming/mocks conventions. + +### Vendored and native code + +- [ ] **Kanna / libxml2 / `Modules/`:** Reviewed for upstream parity, licensing, and Apple vs Linux builds. + +### Severity (optional) + +| Level | Examples | +|-------|----------| +| **Blocker** | Breaking public API without approval; security issue; no tests for new code where tests are practical | +| **Major** | Inconsistent errors; README examples that do not compile | +| **Minor** | Style; minor docs | + +### Detailed review themes (from checklist sections) + +- **API:** Breaking `public`/`open` without semver/CHANGELOG/podspec alignment. +- **Errors:** `throws` changes that confuse callers without a version strategy. +- **README:** Examples must match real APIs (`jsonToHtml` overloads, `GQL.jsonToHtml`). +- **Dependencies:** New packages in `Package.swift` / podspec need justification. + +## References + +- `skills/testing/SKILL.md` +- `skills/contentstack-utils/SKILL.md` diff --git a/skills/contentstack-utils/SKILL.md b/skills/contentstack-utils/SKILL.md new file mode 100644 index 0000000..5626327 --- /dev/null +++ b/skills/contentstack-utils/SKILL.md @@ -0,0 +1,55 @@ +--- +name: contentstack-utils +description: Public API—ContentstackUtils, Option/Renderable, RTE/JSON, GQL, variants, errors; no bundled HTTP client. +--- + +# Contentstack Utils – SDK skill + +## When to use + +- Implementing or changing RTE/HTML rendering, JSON RTE parsing, or variant helpers. +- Updating `README.md` / `CHANGELOG.md` / podspec for user-visible behavior. +- Assessing semver impact of `public` / `open` changes. + +## Main entry (consumer API) + +- Consumers `import ContentstackUtils` and use **`ContentstackUtils`**: e.g. `render(content:_:)`, `render(contents:_:)`, `jsonToHtml(node:_:)`, `getVariantAliases`, nested **`GQL.jsonToHtml(rte:_:)`**. +- Keep the static surface small and documented; breaking changes need semver and changelog notes. + +## Customization + +- Subclass or extend via **`Option`** (open class) conforming to **`Renderable`**: `renderItem(embeddedObject:metadata:)`, `renderMark(markType:text:)`, `renderNode(nodeType:node:next:)`. +- Do not remove or rename open hooks without a **major** version. + +## Data model + +- RTE JSON uses **`Node`**, **`JSONNode`** / **`JSONNodes`**, **`MarkType`**, **`StyleType`**, **`Metadata`**, embedded entry/asset types (`EmbeddedObject`, `EmbeddedEntry`, etc.). +- Preserve **`Codable`** / decoding compatibility with Contentstack Delivery and GraphQL payloads. + +## Errors + +- Expose domain failures with nested types where appropriate (e.g. **`ContentstackUtils.VariantUtilityError.invalidArgument`**). +- Use **`throws`** for recoverable failures; avoid force-unwraps on public paths. + +## HTML and documentation + +- Rendering uses Kanna/HTML internally; keep output predictable for documented inputs. +- Document new node types or GQL JSON shapes in **`README.md`** / **`CHANGELOG.md`**. + +## No network layer + +- This package does **not** ship HTTP clients or tokens. +- README examples showing **`Stack`**, **`fetch`**, or **Apollo** are integration sketches only—do **not** add hard dependencies on the main Contentstack iOS SDK or Apollo in **`Package.swift`** unless product explicitly requires it. + +## Legacy naming + +- Some names (e.g. **`embdeddedItems`**) are entrenched; changing them is a **breaking** API change—coordinate with maintainers. + +## Docs and versioning + +- Align **`ContentstackUtils.podspec`** and git tags with releases. Follow **semver** for `public` / `open` changes. + +## References + +- [Contentstack](https://www.contentstack.com/) +- `skills/swift-style/SKILL.md`, `skills/framework/SKILL.md` diff --git a/skills/dev-workflow/SKILL.md b/skills/dev-workflow/SKILL.md new file mode 100644 index 0000000..fe75550 --- /dev/null +++ b/skills/dev-workflow/SKILL.md @@ -0,0 +1,51 @@ +--- +name: dev-workflow +description: Branches, CI, build/test/lint, PR expectations, coverage—standard workflow for Contentstack Utils Swift. +--- + +# Development workflow – Contentstack Utils Swift + +## When to use + +- Setting up locally, opening a PR, or aligning with CI. +- Answering “how do we run tests?” or “which branch targets `master`?” + +## Branches + +- Use feature branches (e.g. `feat/...`, `fix/...`, ticket branches). +- **CI** runs on push to `master` and on pull requests targeting `master` or `next` (`.github/workflows/ci.yml`). +- **Merges into `master`** may be gated: PRs whose base is `master` are often expected to come from **`staging`**; other heads may fail the check-branch workflow (`.github/workflows/check-branch.yml`). Confirm with your team before opening PRs to `master`. + +## Running tests and build + +- **SPM:** `swift build`, `swift test` +- **CI-style Xcode (iOS Simulator):** + `xcodebuild -project "ContentstackUtils.xcodeproj" -scheme "ContentstackUtils-Package" -destination "OS=13.4.1,name=iPhone 11 Pro" test` + Adjust `-destination` for your local Xcode/Simulator. + +Run tests before opening a PR. Default tests use **offline** mocks and fixtures—no `.env` or live stack credentials. + +## Lint + +- **SwiftLint:** `swiftlint` (`.swiftlint.yml`) + +## Pull requests + +- Build passes: `swift build` and `swift test` (and `xcodebuild` if you touch Xcode-specific paths). +- Follow the **code-review** skill (`skills/code-review/SKILL.md`) before merge. +- Prefer backward-compatible public API; call out breaking changes and semver. +- Describe behavior and update `CHANGELOG.md` / version metadata (`ContentstackUtils.podspec`, tags) when releasing—per team process. +- Security/policy scans may run in CI (e.g. `.github/workflows/sca-scan.yml`, `policy-scan.yml`). + +## Optional: TDD + +If the team uses TDD: RED → GREEN → REFACTOR. Test structure is in `skills/testing/SKILL.md`. + +## Coverage + +- **Slather** (`.slather.yml`, scheme `ContentstackUtils-Package`): use after tests to inspect `Sources/ContentstackUtils/` coverage. + +## References + +- `skills/testing/SKILL.md` +- `skills/code-review/SKILL.md` diff --git a/skills/framework/SKILL.md b/skills/framework/SKILL.md new file mode 100644 index 0000000..1565408 --- /dev/null +++ b/skills/framework/SKILL.md @@ -0,0 +1,39 @@ +--- +name: framework +description: SPM targets, libxml2 Modules, vendored Kanna, deployment targets, CocoaPods podspec, CI xcodebuild. +--- + +# Framework / build – Contentstack Utils Swift + +## When to use + +- Editing `Package.swift`, `Modules/`, or `Sources/Kanna/`. +- Changing deployment targets or conditional libxml linking. +- Updating `ContentstackUtils.podspec` or CI assumptions (scheme, destination). + +## Swift Package Manager + +- **Product:** `ContentstackUtils`. +- **Targets:** `ContentstackUtils` (sources under `Sources/`), `ContentstackUtilsTests`, system library **`libxml2`** → **`Modules/`**. +- **Apple vs Linux:** Conditional `libxml2` dependency and `pkg-config` as in `Package.swift`—preserve behavior when refactoring. + +## Vendored Kanna + +- **`Sources/Kanna/`** is excluded from SwiftLint. Updates = intentional vendoring (license, diff, cross-platform build). + +## CocoaPods + +- **`ContentstackUtils.podspec`:** e.g. `source_files` `Sources/**/*.{swift}`, `HEADER_SEARCH_PATHS` / `-lxml2` for libxml. Keep aligned with SPM layout and tagged releases. + +## Platforms + +- Declared in `Package.swift` / podspec (e.g. macOS 10.13+, iOS/tvOS 11+, watchOS 4+). See also **`skills/swift-style/SKILL.md`** for API availability and naming. + +## CI + +- **GitHub Actions** uses **xcodebuild** with scheme **`ContentstackUtils-Package`**. After changing parsing or linking, validate with both **`swift test`** and Xcode builds. + +## References + +- `skills/swift-style/SKILL.md` +- `skills/dev-workflow/SKILL.md` diff --git a/skills/swift-style/SKILL.md b/skills/swift-style/SKILL.md new file mode 100644 index 0000000..e01b5e1 --- /dev/null +++ b/skills/swift-style/SKILL.md @@ -0,0 +1,41 @@ +--- +name: swift-style +description: SwiftLint, Sources layout, Kanna/libxml2, platforms, naming, access control for all Swift in this repo. +--- + +# Swift style and repo layout – Contentstack Utils Swift + +## When to use + +- Editing any Swift under `Sources/` or `Tests/`. +- Adding files or changing platform/deployment assumptions. + +## Tooling + +- Run **SwiftLint** with `.swiftlint.yml`. Do not relax rules for new code without team agreement. +- **`Sources/Kanna/`** is excluded from SwiftLint—do not copy patterns into `Sources/ContentstackUtils/` that would fail lint there. + +## Package layout + +- **Library code:** `Sources/ContentstackUtils/`. +- **Vendored Kanna:** `Sources/Kanna/`—treat as third-party unless you are deliberately upgrading the vendored copy; prefer fixes in `ContentstackUtils` or documented Kanna upgrades. + +## Platforms and libxml2 + +- **Deployment targets:** macOS 10.13+, iOS/tvOS 11+, watchOS 4+ (`Package.swift`). Avoid newer SDK-only APIs without availability checks or a deliberate target bump. +- **libxml2:** Apple platforms use system libxml where applicable; Linux uses the `libxml2` system target and `pkg-config`. Keep `Modules/` and `Package.swift` conditionals in sync when changing platform support. + +## Naming and API surface + +- Swift conventions: types `UpperCamelCase`, members `lowerCamelCase`. +- Preserve established **public** names even when imperfect (e.g. historical typos) unless doing a **semver-major** cleanup with maintainer agreement. + +## Imports and access control + +- `import Foundation` as needed; HTML parsing follows existing Kanna usage in this package. +- Mark **`public` / `open`** intentionally; keep implementation `internal` or `private` unless tests use established `@testable` patterns. + +## References + +- `skills/framework/SKILL.md` (SPM, podspec, CI) +- `skills/testing/SKILL.md` (lint exclusions in tests) diff --git a/skills/testing/SKILL.md b/skills/testing/SKILL.md new file mode 100644 index 0000000..aed7610 --- /dev/null +++ b/skills/testing/SKILL.md @@ -0,0 +1,40 @@ +--- +name: testing +description: XCTest—layout, mocks, fixtures, SwiftLint/Slather, offline tests, Linux manifests. +--- + +# Testing – Contentstack Utils Swift + +## When to use + +- Adding or changing tests under `Tests/ContentstackUtilsTests/`. +- Debugging flaky tests; improving fixtures or mocks. + +## Runner and tooling + +- **XCTest** via **`swift test`** (SPM) and/or Xcode scheme **`ContentstackUtils-Package`** (`ContentstackUtils.xcodeproj`), matching `.github/workflows/ci.yml`. +- **SwiftLint:** `.swiftlint.yml`; **`Tests/ContentstackUtilsTests/Constants.swift`** is excluded—other test files are linted. +- **Slather:** `.slather.yml` ignores `Tests/*` in coverage reports; still add tests for new production code in `Sources/ContentstackUtils/` when practical. + +## Test naming and layout + +- **Target:** `ContentstackUtilsTests`; path **`Tests/ContentstackUtilsTests/`**. +- **File names:** `*Tests.swift`, `*Test.swift`, or feature-oriented names (`GQLJsonToHtml.swift`, `JsonNodes.swift`, `VariantUtilityTests.swift`). +- **Fixtures and mocks:** Prefer `JsonNodes.swift`, `JsonNodesHtmlResults.swift`, `EmbededModelMock.swift`, `CustomRenderOptionMock.swift`, `TestClient.swift`, etc., before adding parallel helpers. + +## Integration vs unit + +- No separate integration tree: tests live in **`ContentstackUtilsTests`** with mocks for API-shaped payloads—**no live network** or credentials in CI. + +## Linux / discovery + +- Maintain **`XCTestManifests.swift`** if your workflow requires explicit Linux test discovery. + +## Secrets + +- Tests are **offline**; do not commit API keys or real tokens. + +## References + +- `skills/dev-workflow/SKILL.md` +- `skills/code-review/SKILL.md`