@systemfsoftware/effect-schema-vite 1.1.7 → 1.3.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.
@@ -0,0 +1,26 @@
1
+ import { Plugin as Plugin_2 } from 'vite';
2
+
3
+ /**
4
+ * Vite plugin that walks the consumer's `src/` directory, finds every
5
+ * exported Effect `Schema`, and auto-injects `ruleOfSchemas` round-trip
6
+ * property tests for each one.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * // vitest.config.ts
11
+ * import { inlineSchemaTests } from '@systemfsoftware/effect-schema-vite'
12
+ *
13
+ * export default defineConfig({
14
+ * plugins: [inlineSchemaTests()],
15
+ * })
16
+ * ```
17
+ */
18
+ export declare const inlineSchemaTests: (options?: InlineSchemaTestsOptions) => Plugin_2;
19
+
20
+ /** @since 0.1.0 */
21
+ export declare interface InlineSchemaTestsOptions {
22
+ /** Directory to scan for schema files, relative to Vite root. Default: `"src"`. */
23
+ dir?: string;
24
+ }
25
+
26
+ export { }
package/dist/index.mjs CHANGED
@@ -45,7 +45,13 @@ function findExportedSchemaNames(source) {
45
45
  for (const node of result.program.body) {
46
46
  if (node.type !== "ExportNamedDeclaration") continue;
47
47
  const decl = node.declaration;
48
- if (!decl || decl.type !== "VariableDeclaration") continue;
48
+ if (!decl) continue;
49
+ if (decl.type === "ClassDeclaration") {
50
+ const className = decl.id?.name;
51
+ if (typeof className === "string" && !className.startsWith("_") && extendsSchemaClass(decl.superClass)) names.push(className);
52
+ continue;
53
+ }
54
+ if (decl.type !== "VariableDeclaration") continue;
49
55
  for (const declarator of decl.declarations) {
50
56
  const id = declarator.id;
51
57
  if (id.type !== "Identifier") continue;
@@ -63,51 +69,55 @@ function findExportedSchemaNames(source) {
63
69
  }
64
70
  }
65
71
  function typeRefContainsSchema(t) {
66
- if (!t || typeof t !== "object") return false;
67
- const node = t;
68
- if (node.type === "TSTypeReference" && node.typeName) {
69
- const tn = node.typeName;
70
- if (tn.type === "Identifier" && typeof tn.name === "string" && tn.name.includes("Schema")) return true;
71
- if (tn.type === "TSQualifiedName" && typeof tn.name === "string" && tn.name.includes("Schema")) return true;
72
- }
73
- if (node.typeParameters) {
74
- const params = node.typeParameters;
75
- if (Array.isArray(params.params)) {
76
- for (const p of params.params) if (typeRefContainsSchema(p)) return true;
77
- }
78
- }
79
- if (node.types && Array.isArray(node.types)) {
80
- for (const m of node.types) if (typeRefContainsSchema(m)) return true;
81
- }
72
+ if (!t) return false;
73
+ if (t.type === "TSTypeReference" && t.typeName.type === "Identifier") return t.typeName.name.includes("Schema");
74
+ if (t.type === "TSUnionType" || t.type === "TSIntersectionType") return t.types.some((member) => typeRefContainsSchema(member));
82
75
  return false;
83
76
  }
84
77
  function initRefersToSchema(expr) {
85
- if (!expr || typeof expr !== "object") return false;
86
- const node = expr;
87
- if (node.type === "CallExpression" && node.callee) {
88
- const callee = node.callee;
89
- if (callee.type === "Identifier" && callee.name === "pipe") {
90
- const args = node.arguments;
91
- if (Array.isArray(args)) {
92
- for (const arg of args) if (initRefersToSchema(arg)) return true;
93
- }
94
- return false;
95
- }
78
+ if (!expr) return false;
79
+ if (expr.type === "CallExpression") {
80
+ const callee = expr.callee;
81
+ if (callee.type === "Identifier" && callee.name === "pipe") return expr.arguments.some((arg) => arg.type !== "SpreadElement" && initRefersToSchema(arg));
96
82
  if (callee.type === "MemberExpression") return memberChainStartsWithS(callee);
97
- if (callee.type === "Identifier" && callee.name.includes("Schema")) return true;
83
+ if (callee.type === "Identifier") return callee.name.includes("Schema");
84
+ return false;
98
85
  }
99
- if (node.type === "MemberExpression") return memberChainStartsWithS(node);
86
+ if (expr.type === "MemberExpression") return memberChainStartsWithS(expr);
100
87
  return false;
101
88
  }
102
89
  function memberChainStartsWithS(node) {
103
90
  const obj = node.object;
104
- if (!obj) return false;
105
- if (obj.type === "Identifier" && obj.name === "S") return true;
106
- if (obj.type === "Identifier" && typeof obj.name === "string" && obj.name.includes("Schema")) return true;
91
+ if (obj.type === "Identifier") return obj.name === "S" || obj.name.includes("Schema");
107
92
  if (obj.type === "MemberExpression") return memberChainStartsWithS(obj);
93
+ if (obj.type === "CallExpression") {
94
+ const callee = obj.callee;
95
+ if (callee.type === "MemberExpression") return memberChainStartsWithS(callee);
96
+ if (callee.type === "Identifier") return callee.name === "S" || callee.name.includes("Schema");
97
+ }
108
98
  return false;
109
99
  }
110
100
  /**
101
+ * True when a class extends `Schema.Class(...)` or `Schema.TaggedClass(...)`.
102
+ * The constructor is curried — `Schema.Class<Foo>()({...})` is two nested
103
+ * CallExpressions wrapping one MemberExpression — so unwrap the call chain
104
+ * before inspecting the member.
105
+ *
106
+ * `Schema.TaggedError` is deliberately excluded: an error is a failure value,
107
+ * not a codec, so it is not subject to the round-trip laws (and its `cause`
108
+ * field is routinely `S.Unknown`, which does not round-trip).
109
+ */
110
+ function extendsSchemaClass(superClass) {
111
+ if (!superClass) return false;
112
+ let callee = superClass;
113
+ while (callee.type === "CallExpression") callee = callee.callee;
114
+ if (callee.type !== "MemberExpression") return false;
115
+ if (callee.property.type !== "Identifier") return false;
116
+ const propName = callee.property.name;
117
+ if (propName !== "Class" && propName !== "TaggedClass") return false;
118
+ return memberChainStartsWithS(callee);
119
+ }
120
+ /**
111
121
  * Vite plugin that walks the consumer's `src/` directory, finds every
112
122
  * exported Effect `Schema`, and auto-injects `ruleOfSchemas` round-trip
113
123
  * property tests for each one.
@@ -131,7 +141,7 @@ const inlineSchemaTests = (options) => {
131
141
  config = c;
132
142
  },
133
143
  resolveId(id) {
134
- if (id === "virtual:@systemfsoftware/inline-schema-tests") return "\0virtual:@systemfsoftware/inline-schema-tests";
144
+ return id === "virtual:@systemfsoftware/inline-schema-tests" ? "\0virtual:@systemfsoftware/inline-schema-tests" : void 0;
135
145
  },
136
146
  load(id) {
137
147
  if (id !== "\0virtual:@systemfsoftware/inline-schema-tests") return;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@systemfsoftware/effect-schema-vite",
3
3
  "license": "MIT",
4
- "version": "1.1.7",
4
+ "version": "1.3.0",
5
5
  "author": "Ryan Lee <drdgvhbh@gmail.com>",
6
6
  "repository": {
7
7
  "type": "git",
@@ -46,10 +46,10 @@
46
46
  "vite": "^7",
47
47
  "vitest": "^4",
48
48
  "@systemfsoftware/arethetypeswrong-cli": "^1.0.7",
49
+ "@systemfsoftware/tsconfig": "^1.2.6",
49
50
  "@systemfsoftware/oxlint-config": "^0.1.0",
50
- "@systemfsoftware/effect-schema-law": "^0.3.9",
51
- "@systemfsoftware/tsconfig": "^1.2.5",
52
- "@systemfsoftware/vitest-config": "^0.1.0"
51
+ "@systemfsoftware/vitest-config": "^0.1.0",
52
+ "@systemfsoftware/effect-schema-law": "^0.5.0"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@systemfsoftware/effect-schema-law": "*",
@@ -62,7 +62,7 @@
62
62
  },
63
63
  "scripts": {
64
64
  "clean": "rimraf dist",
65
- "build": "tsdown",
65
+ "build": "tsdown && pnpm api:check",
66
66
  "typecheck": "tsc --noEmit --incremental",
67
67
  "test": "vitest run",
68
68
  "test:run": "vitest run",