Skip to content

Commit b9f45d0

Browse files
committed
feat(tailwindcss-patch): stabilize validate json contract
1 parent 4fc6a94 commit b9f45d0

10 files changed

Lines changed: 146 additions & 8 deletions

File tree

.changeset/metal-horses-work.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
Publish schema for validate JSON output.
66

77
- add `tailwindcss-patch/validate-result.schema.json` for `tw-patch validate --json`
8-
- include failure payload contract (`reason`, `exitCode`, `message`) alongside success shape reference
8+
- include success/failure payload contracts (`ok: true` success and `ok: false` failure with `reason`, `exitCode`, `message`)
99
- export `VALIDATE_FAILURE_REASONS` and align schema tests with public validate constants

packages/tailwindcss-patch/MIGRATION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ Migration mapping:
9494
- `tw-patch restore --json` now exposes report metadata fields (`reportKind`, `reportSchemaVersion`) when available for easier diagnostics.
9595
- `tw-patch validate` can validate migration report compatibility in dry-run mode without restoring files.
9696
- `tw-patch validate` now uses dedicated failure exit codes for CI diagnostics (`21`/`22`/`23`/`24`).
97+
- `tw-patch validate --json` now emits a stable discriminated payload (`ok: true` success / `ok: false` failure with `reason` + `exitCode`), covered by `tailwindcss-patch/validate-result.schema.json`.
9798
- Migration report tooling now has public exports from package entry (`migrateConfigFiles`, `restoreConfigFiles`, report constants/types) and published JSON schema subpaths: `tailwindcss-patch/migration-report.schema.json`, `tailwindcss-patch/restore-result.schema.json`, `tailwindcss-patch/validate-result.schema.json`.
9899
- Commands resolve configuration from `tailwindcss-patch.config.ts` via `@tailwindcss-mangle/config`. Existing configuration files continue to work without changes.
99100

packages/tailwindcss-patch/README-cn.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ CLI 会通过 `@tailwindcss-mangle/config` 加载 `tailwindcss-patch.config.ts`
107107
`tw-patch validate` 会以 dry-run 模式执行迁移报告校验,不写回任何恢复文件,同时校验报告 schema 与备份引用状态。
108108
校验失败时提供分层退出码,便于 CI 判定:
109109
`21` 报告不兼容,`22` 严格模式下备份缺失,`23` I/O 错误,`24` 未知错误。
110+
使用 `--json` 时会输出稳定结构:
111+
成功 => `{ ok: true, ...restoreFields }`,失败 => `{ ok: false, reason, exitCode, message }`
110112

111113
JSON Schema 通过子路径发布:
112114
`tailwindcss-patch/migration-report.schema.json`
@@ -115,6 +117,27 @@ JSON Schema 通过子路径发布:
115117
编程场景也可直接从包入口导入报告相关导出:
116118
`migrateConfigFiles``restoreConfigFiles``MIGRATION_REPORT_KIND``MIGRATION_REPORT_SCHEMA_VERSION``ConfigFileMigrationReport``VALIDATE_EXIT_CODES`
117119

120+
### CI 推荐流程
121+
122+
```bash
123+
# 1) 先检查 workspace 中是否还有待迁移配置
124+
pnpm dlx tw-patch migrate --workspace --check --report-file .tw-patch/migrate-report.json
125+
126+
# 2) 再校验报告兼容性与备份引用,并保存 JSON 结果
127+
set +e
128+
pnpm dlx tw-patch validate --report-file .tw-patch/migrate-report.json --strict --json > .tw-patch/validate-result.json
129+
status=$?
130+
set -e
131+
132+
case "$status" in
133+
0) echo "validate ok" ;;
134+
21) echo "报告 schema/kind 不兼容"; exit 1 ;;
135+
22) echo "--strict 下存在缺失备份"; exit 1 ;;
136+
23) echo "读取报告或备份时发生 I/O 错误"; exit 1 ;;
137+
*) echo "未知校验错误"; exit "$status" ;;
138+
esac
139+
```
140+
118141
### `tokens` 常用参数
119142

120143
| 参数 | 说明 |

packages/tailwindcss-patch/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ With `--json`, restore output includes `reportKind` / `reportSchemaVersion` when
164164
`tw-patch validate` performs migration report compatibility checks without writing restored files. It runs report schema validation and scans backup references in dry-run mode.
165165
On failure, validate uses dedicated exit codes for CI:
166166
`21` report incompatibility, `22` strict missing backups, `23` I/O errors, `24` unknown errors.
167+
With `--json`, validate emits a stable payload:
168+
success => `{ ok: true, ...restoreFields }`, failure => `{ ok: false, reason, exitCode, message }`.
167169

168170
Schemas are published at package subpaths:
169171
`tailwindcss-patch/migration-report.schema.json`,
@@ -172,6 +174,27 @@ Schemas are published at package subpaths:
172174
Programmatic consumers can also import report helpers/types from package entry:
173175
`migrateConfigFiles`, `restoreConfigFiles`, `MIGRATION_REPORT_KIND`, `MIGRATION_REPORT_SCHEMA_VERSION`, `ConfigFileMigrationReport`, `VALIDATE_EXIT_CODES`.
174176

177+
### CI recipe
178+
179+
```bash
180+
# 1) fail fast when workspace configs still need migration
181+
pnpm dlx tw-patch migrate --workspace --check --report-file .tw-patch/migrate-report.json
182+
183+
# 2) validate report schema/backup references and keep machine-readable output
184+
set +e
185+
pnpm dlx tw-patch validate --report-file .tw-patch/migrate-report.json --strict --json > .tw-patch/validate-result.json
186+
status=$?
187+
set -e
188+
189+
case "$status" in
190+
0) echo "validate ok" ;;
191+
21) echo "report schema/kind incompatible"; exit 1 ;;
192+
22) echo "missing backups under --strict"; exit 1 ;;
193+
23) echo "I/O failure while reading report/backups"; exit 1 ;;
194+
*) echo "unknown validate failure"; exit "$status" ;;
195+
esac
196+
```
197+
175198
### Token report options
176199

177200
| Flag | Description |

packages/tailwindcss-patch/schema/restore-result.schema.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"$schema": "https://json-schema.org/draft/2020-12/schema",
33
"$id": "https://mangle.icebreaker.top/schemas/tailwindcss-patch/restore-result.schema.json",
4-
"title": "tailwindcss-patch restore/validate result",
5-
"description": "Schema for JSON output from `tw-patch restore --json` and `tw-patch validate --json`.",
4+
"title": "tailwindcss-patch restore result",
5+
"description": "Schema for JSON output from `tw-patch restore --json`.",
66
"type": "object",
77
"required": [
88
"cwd",

packages/tailwindcss-patch/schema/validate-result.schema.json

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,82 @@
55
"description": "Schema for JSON output from `tw-patch validate --json`.",
66
"oneOf": [
77
{
8-
"$ref": "./restore-result.schema.json"
8+
"$ref": "#/$defs/success"
99
},
1010
{
1111
"$ref": "#/$defs/failure"
1212
}
1313
],
1414
"$defs": {
15+
"success": {
16+
"type": "object",
17+
"required": [
18+
"ok",
19+
"cwd",
20+
"reportFile",
21+
"dryRun",
22+
"strict",
23+
"scannedEntries",
24+
"restorableEntries",
25+
"restoredFiles",
26+
"missingBackups",
27+
"skippedEntries",
28+
"restored"
29+
],
30+
"properties": {
31+
"ok": {
32+
"type": "boolean",
33+
"const": true
34+
},
35+
"cwd": {
36+
"type": "string"
37+
},
38+
"reportFile": {
39+
"type": "string"
40+
},
41+
"reportKind": {
42+
"type": "string",
43+
"const": "tw-patch-migrate-report"
44+
},
45+
"reportSchemaVersion": {
46+
"type": "integer",
47+
"minimum": 1
48+
},
49+
"dryRun": {
50+
"type": "boolean"
51+
},
52+
"strict": {
53+
"type": "boolean"
54+
},
55+
"scannedEntries": {
56+
"type": "integer",
57+
"minimum": 0
58+
},
59+
"restorableEntries": {
60+
"type": "integer",
61+
"minimum": 0
62+
},
63+
"restoredFiles": {
64+
"type": "integer",
65+
"minimum": 0
66+
},
67+
"missingBackups": {
68+
"type": "integer",
69+
"minimum": 0
70+
},
71+
"skippedEntries": {
72+
"type": "integer",
73+
"minimum": 0
74+
},
75+
"restored": {
76+
"type": "array",
77+
"items": {
78+
"type": "string"
79+
}
80+
}
81+
},
82+
"additionalProperties": false
83+
},
1584
"failure": {
1685
"type": "object",
1786
"required": [

packages/tailwindcss-patch/src/cli/commands.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@ export interface ValidateFailureSummary {
5454
message: string
5555
}
5656

57+
export interface ValidateJsonSuccessPayload extends RestoreConfigFilesResult {
58+
ok: true
59+
}
60+
61+
export interface ValidateJsonFailurePayload {
62+
ok: false
63+
reason: ValidateFailureReason
64+
exitCode: number
65+
message: string
66+
}
67+
5768
const IO_ERROR_CODES = new Set(['ENOENT', 'EACCES', 'EPERM', 'EISDIR', 'ENOTDIR', 'EMFILE', 'ENFILE'])
5869

5970
function isNodeError(error: unknown): error is NodeJS.ErrnoException {
@@ -754,7 +765,11 @@ async function validateCommandDefaultHandler(ctx: TailwindcssPatchCommandContext
754765
})
755766

756767
if (args.json) {
757-
logger.log(JSON.stringify(result, null, 2))
768+
const payload: ValidateJsonSuccessPayload = {
769+
ok: true,
770+
...result,
771+
}
772+
logger.log(JSON.stringify(payload, null, 2))
758773
return result
759774
}
760775

@@ -772,12 +787,13 @@ async function validateCommandDefaultHandler(ctx: TailwindcssPatchCommandContext
772787
catch (error) {
773788
const summary = classifyValidateError(error)
774789
if (args.json) {
775-
logger.log(JSON.stringify({
790+
const payload: ValidateJsonFailurePayload = {
776791
ok: false,
777792
reason: summary.reason,
778793
exitCode: summary.exitCode,
779794
message: summary.message,
780-
}, null, 2))
795+
}
796+
logger.log(JSON.stringify(payload, null, 2))
781797
}
782798
else {
783799
logger.error(`Validation failed [${summary.reason}] (exit ${summary.exitCode}): ${summary.message}`)

packages/tailwindcss-patch/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export {
1313
type TailwindcssPatchCommandOptions,
1414
type ValidateFailureReason,
1515
type ValidateFailureSummary,
16+
type ValidateJsonFailurePayload,
17+
type ValidateJsonSuccessPayload,
1618
ValidateCommandError,
1719
VALIDATE_EXIT_CODES,
1820
VALIDATE_FAILURE_REASONS,

packages/tailwindcss-patch/test/cli.mount.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ describe('mountTailwindcssPatchCommands', () => {
529529
strict: false,
530530
})
531531
expect(logger.log).toHaveBeenCalledWith(JSON.stringify({
532+
ok: true,
532533
cwd: '/tmp/project',
533534
reportFile: '/tmp/project/.tw-patch/migrate-report.json',
534535
reportKind: 'tw-patch-migrate-report',

packages/tailwindcss-patch/test/migration-report.schema.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ describe('validate result json schema', () => {
5757

5858
expect(schema.$schema).toContain('json-schema.org')
5959
expect(schema.oneOf).toHaveLength(2)
60-
expect(schema.oneOf[0].$ref).toContain('restore-result.schema.json')
60+
expect(schema.$defs.success.required).toEqual(
61+
expect.arrayContaining(['ok', 'reportFile', 'dryRun', 'restored']),
62+
)
63+
expect(schema.$defs.success.properties.ok.const).toBe(true)
6164
expect(schema.$defs.failure.properties.reason.enum).toEqual([...VALIDATE_FAILURE_REASONS])
6265
expect(schema.$defs.failure.properties.exitCode.enum).toEqual([
6366
VALIDATE_EXIT_CODES.REPORT_INCOMPATIBLE,

0 commit comments

Comments
 (0)