Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .cursor/rules/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Cursor rules

Rules give context-aware guidance for this **Contentstack HTML → JSON RTE migration CLI plugin** (`@contentstack/cli-cm-migrate-rte`).

## Rules overview

| File | Purpose |
|------|---------|
| `dev-workflow.md` | TDD, structure, validation commands (always applied) |
| `contentstack-cli.mdc` | Contentstack CLI utilities, migration flow, Management API habits |
| `testing.mdc` | Mocha / Chai / Sinon, nock, and coverage |
| `oclif-commands.mdc` | Command flags and delegation patterns |

## How they attach

- **Always**: `dev-workflow.md`
- **Commands** (`src/commands/**`): `oclif-commands.mdc`
- **Migration logic** (`src/lib/**`): `contentstack-cli.mdc`
- **Tests** (`test/**`): `testing.mdc`

## Chat shortcuts

You can `@`-mention rule topics (for example testing or OCLIF) depending on how your workspace maps rule names.
40 changes: 40 additions & 0 deletions .cursor/rules/contentstack-cli.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
description: "HTML→JSON RTE migration plugin: CLI utilities, migration flow, and Management API habits"
globs:
- "src/lib/**/*.js"
- "src/lib/**/*.json"
alwaysApply: false
---

# Contentstack CLI — migrate HTML RTE

This package is **`@contentstack/cli-cm-migrate-rte`**. Business logic lives in **`src/lib/util/index.js`** (there is no `src/core/` or `src/services/` layer).

## Stack and auth

- Use **`@contentstack/cli-utilities`**: `managementSDKClient`, `cliux`, `flags`, `pathValidator`, `isAuthenticated`, `doesBranchExist`, etc.
- Resolve credentials like **`migrate-html-rte.js`**: config **`alias`** (management token via `getToken`) or **`stack-api-key`** (requires logged-in CLI session per `getStack`).
- Pass **`this.cmaHost`** from the command into stack options as **`host`**.
- **Never** log or persist secrets (API keys, management tokens).

## Migration orchestration

1. **`normalizeFlags`** — maps deprecated camelCase flag names to kebab-case.
2. **`getConfig`** — JSON file via **`--config-path`** / `pathValidator`, or inline paths from **`--html-path`** / **`--json-path`**; validated with **jsonschema** against **`config_schema.json`**; optional **`cliux.confirm`** unless **`--yes`**.
3. **`getStack`** — `managementSDKClient` with `application: json-rte-migration/<version>`, branch check via **`doesBranchExist`**.
4. **`updateSingleContentTypeEntries`** or **`updateContentTypeForGlobalField`** — fetch content type / global field, validate RTE paths (**`isPathValid`** / **`traverseSchemaForField`**), batch entries with **`delay`** and **`batch-limit`**, convert HTML with **jsdom** + **`collapse-whitespace`** + **`htmlToJson`** from **`@contentstack/json-rte-serializer`**, update entries; track **`errorEntriesUid`** on repeated update failures.

## Paths and schema

- **`paths`** entries map **`from`** (HTML RTE uid path) → **`to`** (JSON RTE uid path); support groups, **blocks**, **global_field**, and **experience_container** traversal as in **`setEntryData`** / **`isPathValid`**.
- HTML and JSON RTE must sit at the **same depth**; single/multiple cardinality must **match** between source and target fields.

## API usage

- Batching uses entry **query** + **find** with **`include_count`**, **skip** / **limit**, optional **locale** filter.
- Local **retry** loops exist for batch fetch and **`handleEntryUpdate`** (transient failures); when adding new Management API calls, respect **rate limits** and handle **429** / transient errors consistently with existing patterns.
- **Mock all** HTTP / SDK usage in tests (**nock**, **sinon**); no live stack calls in unit tests.

## Not in this plugin

- This is **not** query-based export: there is no **`QueryExporter`**. Do not assume **`@contentstack/cli-cm-export`** export pipelines unless you are integrating something explicitly shared.
63 changes: 63 additions & 0 deletions .cursor/rules/dev-workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
description: "Core development workflow and TDD patterns - always applied"
globs: ["**/*.js", "**/*.json"]
alwaysApply: true
---

# Development Workflow

## Quick Reference

For detailed patterns, see project skills:

- `@skills/testing` — Testing and TDD
- `@skills/contentstack-cli` — Migration command, `src/lib/util`, Contentstack APIs
- `@skills/framework` — Config validation, CLI UX, retries, shared helpers
- `@skills/code-review` — PR review checklist

## TDD workflow (recommended)

For **new behavior or bug fixes**, prefer working in three steps:

1. **RED** → Write a failing test (or extend an existing one)
2. **GREEN** → Minimal code to pass
3. **REFACTOR** → Clean up while tests stay green

**Exceptions (no new test required when behavior is unchanged):** pure refactors, documentation-only edits, comments/config-only tweaks, trivial typos.

## Guidelines

- **Coverage:** aim high; **~80%** (lines/branches/functions) is an **aspirational target**, not a CI gate in this repo
- **JavaScript** — follow existing style in `src/`; prefer small, focused functions and clear naming
- **NO test.skip or .only** in commits

## File structure (this repo)

- **Command**: `src/commands/cm/entries/migrate-html-rte.js` — `JsonMigrationCommand`, flags, thin `run()`
- **Migration logic**: `src/lib/util/index.js` — stack client, config, batch entry updates, HTML→JSON via `@contentstack/json-rte-serializer` + jsdom
- **Config schema**: `src/lib/util/config_schema.json`
- **Tests**: `test/**/*.test.js` (Mocha); fixtures under `test/dummy/`, helpers under `test/utils/`

## Naming conventions

- **Files**: `kebab-case.js` where the codebase already uses it; test files `*.test.js`
- **Classes**: `PascalCase`
- **Functions**: `camelCase`
- **Tests**: `should [behavior] when [condition]`

## Before coding

1. Read relevant `@skills/*` references
2. For behavior changes: prefer a failing test first, then implement
3. Refactor and run tests

## Validation commands

- `npm test` — All tests with nyc (`mocha --require test/setup.js --forbid-only "test/**/*.test.js"`)
- `npm run prepack` — Regenerate `oclif.manifest.json` and README (run before release packaging as needed)

## Commit suggestions

- Conventional commits are helpful but optional: `feat(scope): description`
- Tests passing before merge
- No stray `console.log` / `debugger` (beyond intentional CLI output already in the command)
45 changes: 45 additions & 0 deletions .cursor/rules/oclif-commands.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
description: "OCLIF / Contentstack command patterns for migrate-html-rte"
globs:
- "src/commands/**/*.js"
- "test/commands/**/*.js"
alwaysApply: false
---

# Command standards (`cm:entries:migrate-html-rte`)

This plugin uses **`Command`** from **`@contentstack/cli-command`** and **`flags`** from **`@contentstack/cli-utilities`**. Follow **`src/commands/cm/entries/migrate-html-rte.js`** as the source of truth.

## Structure

```javascript
const { Command } = require("@contentstack/cli-command");
const { flags } = require("@contentstack/cli-utilities");
const { /* getStack, getConfig, ... */ } = require("../../../lib/util");

class JsonMigrationCommand extends Command {
async run() {
const { flags: migrateRteFlags } = await this.parse(JsonMigrationCommand);
// normalizeFlags → getConfig → getStack → updateSingleContentTypeEntries / updateContentTypeForGlobalField
}
}

JsonMigrationCommand.description = "...";
JsonMigrationCommand.flags = { /* flags.string / flags.boolean / flags.integer */ };
JsonMigrationCommand.examples = [ "...", "csdx cm:entries:migrate-html-rte ..." ];

module.exports = JsonMigrationCommand;
```

## Practices

- **Validate early**: ensure **`paths`** (from config or flags) exist; stack auth via alias or stack-api-key as documented.
- **Delegate**: keep **`run()`** thin; migration, batching, and HTML→JSON conversion stay in **`src/lib/util/index.js`**.
- **User feedback**: success summary and **`errorEntriesUid`** reporting already use **chalk**; keep messages actionable.
- **Errors**: use **`this.error(error.message, { exit: 2 })`** for command-level failures.

## Flags

- Define flags with **`flags.string`**, **`flags.boolean`**, **`flags.integer`**, etc., on the **class** (`JsonMigrationCommand.flags`).
- Use **`dependsOn`** where flags are coupled (e.g. **`html-path`** depends on **`json-path`**).
- Prefer kebab-case flag names; **`normalizeFlags`** in util accepts legacy camelCase keys for backward compatibility.
68 changes: 68 additions & 0 deletions .cursor/rules/testing.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
description: "Testing patterns and TDD workflow"
globs:
- "test/**/*.js"
- "**/*.test.js"
alwaysApply: true
---

# Testing Standards

## TDD workflow

1. For behavior changes, prefer a failing test first
2. Minimal code to pass
3. Refactor while keeping tests green

Pure refactors and docs-only changes may skip new tests when behavior is unchanged.

## Coverage

- **~80%** (lines, branches, functions) is an **aspirational** goal, not enforced as a hard gate here
- Test both success and failure paths
- Mock all external dependencies

## Test patterns

```javascript
const { expect } = require("chai");
const sinon = require("sinon");

describe("[ModuleName]", () => {
beforeEach(() => {
sinon.stub(SomeClient.prototype, "fetch").resolves(mockData);
});

afterEach(() => {
sinon.restore();
});

it("should [expected behavior] when [condition]", async () => {
const input = { /* test data */ };
const result = await moduleUnderTest(input);
expect(result).to.deep.equal(expectedOutput);
});
});
```

## Mocking standards

- Use **sinon** for stubs/spies; use **nock** for HTTP where the tests already do
- Never make real API calls in tests
- Mock at module boundaries (**`managementSDKClient`**, **`command.cmaAPIUrl`**, etc.), not irrelevant internals

## Layout

- Tests live under **`test/**/*.test.js`** (Mocha), loaded via **`test/setup.js`**
- JSON fixtures under **`test/dummy/`**; shared helpers under **`test/utils/`**

## Common mock patterns

```javascript
const nock = require("nock");
const sinon = require("sinon");
const { managementSDKClient } = require("@contentstack/cli-utilities");

sinon.stub(managementSDKClient, "call").resolves(mockClient);
nock("https://example.cma.url").get(/\/v3\//).reply(200, mockPayload);
```
5 changes: 5 additions & 0 deletions .cursor/skills/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Project skills

Agent-oriented skills for **cli-cm-migrate-rte** (`@contentstack/cli-cm-migrate-rte`) live under **[`skills/`](../../skills/)**.

Reference in chat with `@skills/<name>` (for example `@skills/contentstack-cli`, `@skills/testing`).
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ node_modules
oclif.manifest.json
# Husky 9 internal folder (created by "husky" on install; do not commit)
.husky/_
*.log
*.log
.vscode/
20 changes: 13 additions & 7 deletions .talismanrc
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
fileignoreconfig:
- filename: package-lock.json
checksum: dcbdc2bb8ecdfc2768a0acad70ac3658d0dedfe7394ec9b2522ed1d2dfd02d83
- filename: .husky/pre-commit
checksum: 7a12030ddfea18d6f85edc25f1721fb2009df00fdd42bab66b05de25ab3e32b2
- filename: .github/workflows/check-version-bump.yml
checksum: b33b47fae4e126cd9a3489a9324e8b2cf30b38ebdb3dd99e2d453d4bfc0922ad
version: ""
- filename: package-lock.json
checksum: dcbdc2bb8ecdfc2768a0acad70ac3658d0dedfe7394ec9b2522ed1d2dfd02d83
- filename: .husky/pre-commit
checksum: 7a12030ddfea18d6f85edc25f1721fb2009df00fdd42bab66b05de25ab3e32b2
- filename: .github/workflows/check-version-bump.yml
checksum: b33b47fae4e126cd9a3489a9324e8b2cf30b38ebdb3dd99e2d453d4bfc0922ad
- filename: .cursor/rules/contentstack-cli.mdc
checksum: 95be6d57f956007c930116afcd0a3869d789ebaedcecb71a7f7cfd806f979029
- filename: skills/code-review/references/code-review-checklist.md
checksum: ff75324c78ce3f4838a5e52a7c6f300301a7c79102dac82f0a9928a4a1589085
- filename: skills/contentstack-cli/references/contentstack-patterns.md
checksum: 432d1dab0ade2651ca127349b419899f398174669806450570c6d2575a8244eb
version: ""
24 changes: 24 additions & 0 deletions skills/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Skills

Reusable agent guidance for **`@contentstack/cli-cm-migrate-rte`** (HTML RTE → JSON RTE migration). Use with any tool that supports file references.

## Quick reference

| Skill | Use when |
|-------|----------|
| **contentstack-cli** | Command, `src/lib/util`, Contentstack Management API, migration flow |
| **testing** | Mocha, Chai, Sinon, nock, TDD, coverage |
| **framework** | Config schema, CLI confirmation, retries, progress, shared helpers |
| **code-review** | PR / change review |

## How to reference

```
Follow @skills/contentstack-cli and @skills/testing for this change.
```

## Project context

- **Stack:** JavaScript, OCLIF (via `@contentstack/cli-command`), Contentstack CLI utilities, Mocha / Chai / Sinon, nock, nyc
- **Layout:** `src/commands/cm/entries/migrate-html-rte.js` → `src/lib/util/` (`config_schema.json`, migration helpers)
- **Tests:** `test/**/*.test.js`
51 changes: 51 additions & 0 deletions skills/code-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
name: code-review
description: PR review checklist for @contentstack/cli-cm-migrate-rte and similar CLI plugins. Use when reviewing changes to migrate-html-rte, lib/util, or tests.
---

# Code Review Skill

## Quick Reference

- **[Code Review Checklist](./references/code-review-checklist.md)** — Severity levels and full checklist

## Review process

### Severity levels

- **Critical**: Must fix before merge (security, correctness, breaking changes)
- **Important**: Should fix (performance, maintainability, best practices)
- **Suggestion**: Consider improving (style, optimization, readability)

### Quick categories

1. **Security** — No hardcoded secrets; safe logging
2. **Correctness** — Migration logic, path validation, entry updates
3. **Architecture** — Thin command, logic in `src/lib/util`
4. **Performance** — Batching, delays, avoid redundant API calls
5. **Testing** — nock/sinon boundaries, no live stack
6. **Conventions** — JavaScript style consistent with `src/`

## Quick checklist template

```markdown
## Security
- [ ] No secrets in code or logs

## Correctness
- [ ] HTML/JSON path rules and global-field behavior preserved
- [ ] Errors surfaced to the operator

## Architecture
- [ ] Command stays thin; util holds migration logic

## Testing
- [ ] Behavior changes covered; mocks at boundaries

## Conventions
- [ ] Matches existing JS patterns in repo
```

## Usage

Open **references/code-review-checklist.md** for the full structured review.
Loading
Loading