sovr-patch 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sovr-patch might be problematic. Click here for more details.

Files changed (102) hide show
  1. package/LICENSE +66 -0
  2. package/README.md +112 -0
  3. package/dist/audit/engine.js +140 -0
  4. package/dist/audit/engine.js.map +1 -0
  5. package/dist/audit/packs.js +21 -0
  6. package/dist/audit/packs.js.map +1 -0
  7. package/dist/audit/report.js +79 -0
  8. package/dist/audit/report.js.map +1 -0
  9. package/dist/audit/types.js +5 -0
  10. package/dist/audit/types.js.map +1 -0
  11. package/dist/cli/help.js +108 -0
  12. package/dist/cli/help.js.map +1 -0
  13. package/dist/cli/parse-argv.js +73 -0
  14. package/dist/cli/parse-argv.js.map +1 -0
  15. package/dist/commands/activate.js +179 -0
  16. package/dist/commands/activate.js.map +1 -0
  17. package/dist/commands/audit.js +89 -0
  18. package/dist/commands/audit.js.map +1 -0
  19. package/dist/commands/ci-gate.js +239 -0
  20. package/dist/commands/ci-gate.js.map +1 -0
  21. package/dist/commands/list-rules.js +11 -0
  22. package/dist/commands/list-rules.js.map +1 -0
  23. package/dist/commands/run.js +107 -0
  24. package/dist/commands/run.js.map +1 -0
  25. package/dist/commands/status.js +174 -0
  26. package/dist/commands/status.js.map +1 -0
  27. package/dist/core/engine.js +68 -0
  28. package/dist/core/engine.js.map +1 -0
  29. package/dist/core/license.js +243 -0
  30. package/dist/core/license.js.map +1 -0
  31. package/dist/core/load-project.js +41 -0
  32. package/dist/core/load-project.js.map +1 -0
  33. package/dist/core/report.js +68 -0
  34. package/dist/core/report.js.map +1 -0
  35. package/dist/core/rollback.js +160 -0
  36. package/dist/core/rollback.js.map +1 -0
  37. package/dist/core/safe-apply.js +75 -0
  38. package/dist/core/safe-apply.js.map +1 -0
  39. package/dist/core/types.js +3 -0
  40. package/dist/core/types.js.map +1 -0
  41. package/dist/core/update-check.js +162 -0
  42. package/dist/core/update-check.js.map +1 -0
  43. package/dist/core/verify.js +32 -0
  44. package/dist/core/verify.js.map +1 -0
  45. package/dist/index.js +124 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/patch/apply.js +14 -0
  48. package/dist/patch/apply.js.map +1 -0
  49. package/dist/patch/overlap.js +12 -0
  50. package/dist/patch/overlap.js.map +1 -0
  51. package/dist/patch/preview.js +48 -0
  52. package/dist/patch/preview.js.map +1 -0
  53. package/dist/rules/design-token/classify.js +16 -0
  54. package/dist/rules/design-token/classify.js.map +1 -0
  55. package/dist/rules/design-token/locate.js +113 -0
  56. package/dist/rules/design-token/locate.js.map +1 -0
  57. package/dist/rules/design-token/presets.js +53 -0
  58. package/dist/rules/design-token/presets.js.map +1 -0
  59. package/dist/rules/design-token/rule.js +13 -0
  60. package/dist/rules/design-token/rule.js.map +1 -0
  61. package/dist/rules/design-token/schema.js +84 -0
  62. package/dist/rules/design-token/schema.js.map +1 -0
  63. package/dist/rules/design-token/transform.js +27 -0
  64. package/dist/rules/design-token/transform.js.map +1 -0
  65. package/dist/rules/field-rename/classify.js +77 -0
  66. package/dist/rules/field-rename/classify.js.map +1 -0
  67. package/dist/rules/field-rename/locate.js +294 -0
  68. package/dist/rules/field-rename/locate.js.map +1 -0
  69. package/dist/rules/field-rename/rule.js +13 -0
  70. package/dist/rules/field-rename/rule.js.map +1 -0
  71. package/dist/rules/field-rename/schema.js +35 -0
  72. package/dist/rules/field-rename/schema.js.map +1 -0
  73. package/dist/rules/field-rename/transform.js +160 -0
  74. package/dist/rules/field-rename/transform.js.map +1 -0
  75. package/dist/rules/inline-style/classify.js +17 -0
  76. package/dist/rules/inline-style/classify.js.map +1 -0
  77. package/dist/rules/inline-style/locate.js +163 -0
  78. package/dist/rules/inline-style/locate.js.map +1 -0
  79. package/dist/rules/inline-style/presets.js +71 -0
  80. package/dist/rules/inline-style/presets.js.map +1 -0
  81. package/dist/rules/inline-style/rule.js +13 -0
  82. package/dist/rules/inline-style/rule.js.map +1 -0
  83. package/dist/rules/inline-style/schema.js +97 -0
  84. package/dist/rules/inline-style/schema.js.map +1 -0
  85. package/dist/rules/inline-style/transform.js +52 -0
  86. package/dist/rules/inline-style/transform.js.map +1 -0
  87. package/dist/rules/nullish-fallback/classify.js +22 -0
  88. package/dist/rules/nullish-fallback/classify.js.map +1 -0
  89. package/dist/rules/nullish-fallback/locate.js +175 -0
  90. package/dist/rules/nullish-fallback/locate.js.map +1 -0
  91. package/dist/rules/nullish-fallback/rule.js +13 -0
  92. package/dist/rules/nullish-fallback/rule.js.map +1 -0
  93. package/dist/rules/nullish-fallback/schema.js +10 -0
  94. package/dist/rules/nullish-fallback/schema.js.map +1 -0
  95. package/dist/rules/nullish-fallback/transform.js +49 -0
  96. package/dist/rules/nullish-fallback/transform.js.map +1 -0
  97. package/dist/rules/registry.js +21 -0
  98. package/dist/rules/registry.js.map +1 -0
  99. package/dist/rules/types.js +2 -0
  100. package/dist/rules/types.js.map +1 -0
  101. package/license.json +13 -0
  102. package/package.json +64 -0
@@ -0,0 +1,13 @@
1
+ import { parseNullishFallbackConfig } from "./schema.js";
2
+ import { locateNullishFallback } from "./locate.js";
3
+ import { classifyNullishFallback } from "./classify.js";
4
+ import { transformNullishFallback } from "./transform.js";
5
+ export const nullishFallbackRule = {
6
+ name: "nullish-fallback",
7
+ description: "Inject ?? fallback for repeated property access targets.",
8
+ parseConfig: parseNullishFallbackConfig,
9
+ locate: locateNullishFallback,
10
+ classify: classifyNullishFallback,
11
+ transform: transformNullishFallback,
12
+ };
13
+ //# sourceMappingURL=rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule.js","sourceRoot":"","sources":["../../../src/rules/nullish-fallback/rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAI1D,MAAM,CAAC,MAAM,mBAAmB,GAA0C;IACxE,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,0DAA0D;IACvE,WAAW,EAAE,0BAA0B;IACvC,MAAM,EAAE,qBAAqB;IAC7B,QAAQ,EAAE,uBAAuB;IACjC,SAAS,EAAE,wBAAwB;CACpC,CAAC"}
@@ -0,0 +1,10 @@
1
+ export function parseNullishFallbackConfig(input) {
2
+ const target = String(input.target ?? "").trim();
3
+ const fallback = String(input.fallback ?? "").trim();
4
+ if (!target)
5
+ throw new Error(`nullish-fallback: "target" is required`);
6
+ if (!fallback)
7
+ throw new Error(`nullish-fallback: "fallback" is required`);
8
+ return { target, fallback };
9
+ }
10
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/rules/nullish-fallback/schema.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,0BAA0B,CACxC,KAA8B;IAE9B,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAErD,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACvE,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAE3E,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,49 @@
1
+ export function transformNullishFallback(hit, context) {
2
+ const kind = String(hit.metadata?.kind ?? "");
3
+ const fallback = context.config.fallback;
4
+ const wrapParens = Boolean(hit.metadata?.needsParentheses);
5
+ if (kind === "nullish-target-chain") {
6
+ // The matched target is part of a larger chain.
7
+ // e.g., data.result?.data where target = "data.result"
8
+ //
9
+ // We replace the ENTIRE outer chain:
10
+ // Before: data.result?.data
11
+ // After: (data.result ?? '').data
12
+ const matchedText = String(hit.metadata?.matchedText ?? "");
13
+ const tailText = String(hit.metadata?.tailText ?? "");
14
+ let after = `(${matchedText} ?? ${fallback})${tailText}`;
15
+ // If the chain is inside a binary expression (e.g., x?.y > 100),
16
+ // wrap the entire replacement in parentheses
17
+ if (wrapParens) {
18
+ after = `(${after})`;
19
+ }
20
+ return {
21
+ filePath: hit.filePath,
22
+ start: hit.start,
23
+ end: hit.end,
24
+ before: hit.sourceText,
25
+ after,
26
+ ruleName: "nullish-fallback",
27
+ reason: "inject-nullish-fallback-chain",
28
+ };
29
+ }
30
+ // Standalone target (no further chain after it)
31
+ // e.g., data.result → data.result ?? ''
32
+ //
33
+ // If inside a binary expression (e.g., plan.yearlyPrice > 100),
34
+ // wrap in parentheses: (plan.yearlyPrice ?? 0) > 100
35
+ let after = `${hit.sourceText} ?? ${fallback}`;
36
+ if (wrapParens) {
37
+ after = `(${after})`;
38
+ }
39
+ return {
40
+ filePath: hit.filePath,
41
+ start: hit.start,
42
+ end: hit.end,
43
+ before: hit.sourceText,
44
+ after,
45
+ ruleName: "nullish-fallback",
46
+ reason: "inject-nullish-fallback",
47
+ };
48
+ }
49
+ //# sourceMappingURL=transform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../src/rules/nullish-fallback/transform.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,wBAAwB,CACtC,GAAgB,EAChB,OAA2C;IAE3C,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;IACzC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IAE3D,IAAI,IAAI,KAAK,sBAAsB,EAAE,CAAC;QACpC,gDAAgD;QAChD,wDAAwD;QACxD,EAAE;QACF,qCAAqC;QACrC,8BAA8B;QAC9B,qCAAqC;QACrC,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC;QAEtD,IAAI,KAAK,GAAG,IAAI,WAAW,OAAO,QAAQ,IAAI,QAAQ,EAAE,CAAC;QAEzD,iEAAiE;QACjE,6CAA6C;QAC7C,IAAI,UAAU,EAAE,CAAC;YACf,KAAK,GAAG,IAAI,KAAK,GAAG,CAAC;QACvB,CAAC;QAED,OAAO;YACL,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,MAAM,EAAE,GAAG,CAAC,UAAU;YACtB,KAAK;YACL,QAAQ,EAAE,kBAAkB;YAC5B,MAAM,EAAE,+BAA+B;SACxC,CAAC;IACJ,CAAC;IAED,gDAAgD;IAChD,0CAA0C;IAC1C,EAAE;IACF,gEAAgE;IAChE,qDAAqD;IACrD,IAAI,KAAK,GAAG,GAAG,GAAG,CAAC,UAAU,OAAO,QAAQ,EAAE,CAAC;IAC/C,IAAI,UAAU,EAAE,CAAC;QACf,KAAK,GAAG,IAAI,KAAK,GAAG,CAAC;IACvB,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,MAAM,EAAE,GAAG,CAAC,UAAU;QACtB,KAAK;QACL,QAAQ,EAAE,kBAAkB;QAC5B,MAAM,EAAE,yBAAyB;KAClC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { fieldRenameRule } from "./field-rename/rule.js";
2
+ import { nullishFallbackRule } from "./nullish-fallback/rule.js";
3
+ import { designTokenRule } from "./design-token/rule.js";
4
+ import { inlineStyleRule } from "./inline-style/rule.js";
5
+ export function createRuleRegistry() {
6
+ const registry = new Map();
7
+ registry.set(fieldRenameRule.name, fieldRenameRule);
8
+ registry.set(nullishFallbackRule.name, nullishFallbackRule);
9
+ registry.set(designTokenRule.name, designTokenRule);
10
+ registry.set(inlineStyleRule.name, inlineStyleRule);
11
+ return registry;
12
+ }
13
+ export function getRuleOrThrow(registry, name) {
14
+ const rule = registry.get(name);
15
+ if (!rule) {
16
+ const available = [...registry.keys()].join(", ");
17
+ throw new Error(`unknown rule: "${name}". Available rules: ${available}`);
18
+ }
19
+ return rule;
20
+ }
21
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/rules/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,MAAM,UAAU,kBAAkB;IAChC,MAAM,QAAQ,GAAiB,IAAI,GAAG,EAAE,CAAC;IAEzC,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IACpD,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;IAC5D,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IACpD,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAEpD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAsB,EAAE,IAAY;IACjE,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,SAAS,GAAG,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,kBAAkB,IAAI,uBAAuB,SAAS,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/rules/types.ts"],"names":[],"mappings":""}
package/license.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "email": "test@test.com",
3
+ "plan": "full-engine",
4
+ "rules": [
5
+ "field-rename",
6
+ "nullish-fallback",
7
+ "design-token",
8
+ "inline-style"
9
+ ],
10
+ "exp": "2027-03-07T11:22:52.007Z",
11
+ "iat": "2026-03-07T11:22:52.007Z",
12
+ "signature": "fIcH07l6gQyFuhidadMK5w+7SGN+Y39SOe5965PbtRi8kye3JIfpk3yHPcGW0dyMm3DO6obhoJnLi/kFMJ84Bg=="
13
+ }
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "sovr-patch",
3
+ "version": "0.2.0",
4
+ "description": "Rule-driven TypeScript migration engine. AST-powered scanning, safe patches, tsc verification.",
5
+ "type": "module",
6
+ "bin": {
7
+ "sovr-patch": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc -p tsconfig.json",
11
+ "dev": "tsx src/index.ts",
12
+ "list-rules": "tsx src/index.ts list-rules",
13
+ "demo": "tsx scripts/demo.ts",
14
+ "demo:apply": "tsx scripts/demo.ts --apply",
15
+ "trial:field-rename": "tsx src/index.ts run --rule field-rename --from \"config.baseUrl\" --to \"config.endpoint\" --repo ./fixtures/demo-repo-baseurl --report",
16
+ "trial:field-rename:apply": "tsx src/index.ts run --rule field-rename --from \"config.baseUrl\" --to \"config.endpoint\" --repo ./fixtures/demo-repo-baseurl --apply --report",
17
+ "test:scan": "tsx scripts/test-scan.ts",
18
+ "test:rewrite": "tsx scripts/test-rewrite.ts",
19
+ "test:safe-apply": "tsx scripts/test-safe-apply.ts",
20
+ "test": "npm run test:scan && npm run test:rewrite && npm run test:safe-apply",
21
+ "test:engine": "tsx scripts/test-engine.ts",
22
+ "test:nullish-chain": "tsx scripts/test-nullish-chain.ts",
23
+ "test:nullish-precedence": "tsx scripts/test-nullish-precedence.ts",
24
+ "test:destructuring": "tsx scripts/test-destructuring.ts",
25
+ "test:design-token": "tsx scripts/test-design-token.ts",
26
+ "test:inline-style": "tsx scripts/test-inline-style.ts",
27
+ "test:all": "npm run test && npm run test:engine && npm run test:nullish-chain && npm run test:nullish-precedence && npm run test:destructuring && npm run test:design-token && npm run test:inline-style",
28
+ "ci": "tsx scripts/ci-gate.ts"
29
+ },
30
+ "dependencies": {
31
+ "diff": "^7.0.0",
32
+ "ts-morph": "^25.0.0",
33
+ "typescript": "^5.9.2"
34
+ },
35
+ "devDependencies": {
36
+ "@types/diff": "^7.0.2",
37
+ "@types/node": "^24.3.0",
38
+ "tsx": "^4.19.2",
39
+ "vitest": "^4.0.18"
40
+ },
41
+ "engines": {
42
+ "node": ">=20"
43
+ },
44
+ "keywords": [
45
+ "codemod",
46
+ "typescript",
47
+ "migration",
48
+ "ast",
49
+ "patch",
50
+ "sovr",
51
+ "rule-engine"
52
+ ],
53
+ "license": "BSL-1.1",
54
+ "files": [
55
+ "dist",
56
+ "LICENSE",
57
+ "README.md"
58
+ ],
59
+ "author": "SOVR",
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "https://github.com/xie38388/sovr-patch"
63
+ }
64
+ }