@systemfsoftware/effect-schema-vite 1.3.0 → 1.5.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.
@@ -1,10 +1,29 @@
1
1
  import { Plugin as Plugin_2 } from 'vite';
2
2
 
3
+ /**
4
+ * Build the law-suite body injected into a consumer's `schema-laws.test.ts`.
5
+ *
6
+ * Import specifiers are relative to `lawFilePath`, never to the Vite root: the
7
+ * file being rewritten lives in `src/`, so a root-relative specifier resolves
8
+ * to `src/src/…` and yields a suite that silently imports nothing.
9
+ *
10
+ * @since 1.4.0
11
+ */
12
+ export declare const generateSchemaLaws: (lawFilePath: string, srcDir: string) => string;
13
+
3
14
  /**
4
15
  * Vite plugin that walks the consumer's `src/` directory, finds every
5
16
  * exported Effect `Schema`, and auto-injects `ruleOfSchemas` round-trip
6
17
  * property tests for each one.
7
18
  *
19
+ * The laws are injected by rewriting the consumer's own
20
+ * `src/schema-laws.test.ts` — the one test filename the placement taxonomy
21
+ * whitelists by name. It is deliberately NOT a virtual module: the generated
22
+ * body carries real `import` edges to each schema file, so vitest's
23
+ * related-file walk reaches them. A virtual module breaks that walk (its id
24
+ * has no path on disk), which silently drops every generated law from
25
+ * `stryker --related` runs and reports the survivors as coverage gaps.
26
+ *
8
27
  * @example
9
28
  * ```ts
10
29
  * // vitest.config.ts
@@ -23,4 +42,12 @@ export declare interface InlineSchemaTestsOptions {
23
42
  dir?: string;
24
43
  }
25
44
 
45
+ /**
46
+ * The one test filename the placement taxonomy whitelists by name. The plugin
47
+ * rewrites this file in the consumer's `src/`; nothing else is touched.
48
+ *
49
+ * @since 1.4.0
50
+ */
51
+ export declare const LAW_FILE_BASENAME: 'schema-laws.test.ts';
52
+
26
53
  export { }
package/dist/index.d.ts CHANGED
@@ -1,15 +1,40 @@
1
1
  import { Plugin } from "vite";
2
- //#region src/vite-inline-schema-tests.d.ts
2
+ //#region src/mod.d.ts
3
3
  /** @since 0.1.0 */
4
4
  interface InlineSchemaTestsOptions {
5
5
  /** Directory to scan for schema files, relative to Vite root. Default: `"src"`. */
6
6
  dir?: string;
7
7
  }
8
+ /**
9
+ * The one test filename the placement taxonomy whitelists by name. The plugin
10
+ * rewrites this file in the consumer's `src/`; nothing else is touched.
11
+ *
12
+ * @since 1.4.0
13
+ */
14
+ declare const LAW_FILE_BASENAME: 'schema-laws.test.ts';
15
+ /**
16
+ * Build the law-suite body injected into a consumer's `schema-laws.test.ts`.
17
+ *
18
+ * Import specifiers are relative to `lawFilePath`, never to the Vite root: the
19
+ * file being rewritten lives in `src/`, so a root-relative specifier resolves
20
+ * to `src/src/…` and yields a suite that silently imports nothing.
21
+ *
22
+ * @since 1.4.0
23
+ */
24
+ declare const generateSchemaLaws: (lawFilePath: string, srcDir: string) => string;
8
25
  /**
9
26
  * Vite plugin that walks the consumer's `src/` directory, finds every
10
27
  * exported Effect `Schema`, and auto-injects `ruleOfSchemas` round-trip
11
28
  * property tests for each one.
12
29
  *
30
+ * The laws are injected by rewriting the consumer's own
31
+ * `src/schema-laws.test.ts` — the one test filename the placement taxonomy
32
+ * whitelists by name. It is deliberately NOT a virtual module: the generated
33
+ * body carries real `import` edges to each schema file, so vitest's
34
+ * related-file walk reaches them. A virtual module breaks that walk (its id
35
+ * has no path on disk), which silently drops every generated law from
36
+ * `stryker --related` runs and reports the survivors as coverage gaps.
37
+ *
13
38
  * @example
14
39
  * ```ts
15
40
  * // vitest.config.ts
@@ -22,4 +47,4 @@ interface InlineSchemaTestsOptions {
22
47
  */
23
48
  declare const inlineSchemaTests: (options?: InlineSchemaTestsOptions) => Plugin;
24
49
  //#endregion
25
- export { type InlineSchemaTestsOptions, inlineSchemaTests };
50
+ export { InlineSchemaTestsOptions, LAW_FILE_BASENAME, generateSchemaLaws, inlineSchemaTests };
package/dist/index.mjs CHANGED
@@ -1,12 +1,19 @@
1
1
  import { readFileSync, readdirSync, statSync } from "node:fs";
2
- import { extname, join, relative, resolve } from "node:path";
2
+ import { dirname, extname, join, relative, resolve } from "node:path";
3
3
  import { parseSync } from "oxc-parser";
4
- //#region src/vite-inline-schema-tests.ts
4
+ //#region src/mod.ts
5
+ /**
6
+ * The one test filename the placement taxonomy whitelists by name. The plugin
7
+ * rewrites this file in the consumer's `src/`; nothing else is touched.
8
+ *
9
+ * @since 1.4.0
10
+ */
11
+ const LAW_FILE_BASENAME = "schema-laws.test.ts";
5
12
  /**
6
13
  * Walk a directory and return every exported const whose type annotation
7
14
  * or initialiser references Effect Schema APIs.
8
15
  */
9
- function findExportedSchemas(root, dir) {
16
+ function findExportedSchemas(dir) {
10
17
  const schemas = [];
11
18
  function walk(current) {
12
19
  let entries;
@@ -30,7 +37,7 @@ function findExportedSchemas(root, dir) {
30
37
  const names = findExportedSchemaNames(readFileSync(full, "utf-8"));
31
38
  for (const name of names) schemas.push({
32
39
  name,
33
- importPath: `./${relative(root, full).replace(/\.ts$/, "")}`
40
+ filePath: full
34
41
  });
35
42
  }
36
43
  }
@@ -118,10 +125,41 @@ function extendsSchemaClass(superClass) {
118
125
  return memberChainStartsWithS(callee);
119
126
  }
120
127
  /**
128
+ * Build the law-suite body injected into a consumer's `schema-laws.test.ts`.
129
+ *
130
+ * Import specifiers are relative to `lawFilePath`, never to the Vite root: the
131
+ * file being rewritten lives in `src/`, so a root-relative specifier resolves
132
+ * to `src/src/…` and yields a suite that silently imports nothing.
133
+ *
134
+ * @since 1.4.0
135
+ */
136
+ const generateSchemaLaws = (lawFilePath, srcDir) => {
137
+ const schemas = findExportedSchemas(srcDir);
138
+ if (schemas.length === 0) return "// no schemas found\nexport {}\n";
139
+ const specifierOf = (filePath) => {
140
+ const rel = relative(dirname(lawFilePath), filePath).replace(/\.ts$/, "");
141
+ return rel.startsWith(".") ? rel : `./${rel}`;
142
+ };
143
+ return [
144
+ `import { ruleOfSchemas } from '@systemfsoftware/effect-schema-law'`,
145
+ schemas.map((s) => `import { ${s.name} } from '${specifierOf(s.filePath)}'`).join("\n"),
146
+ "",
147
+ schemas.map((s) => `ruleOfSchemas('${s.name}', ${s.name})`).join("\n")
148
+ ].join("\n");
149
+ };
150
+ /**
121
151
  * Vite plugin that walks the consumer's `src/` directory, finds every
122
152
  * exported Effect `Schema`, and auto-injects `ruleOfSchemas` round-trip
123
153
  * property tests for each one.
124
154
  *
155
+ * The laws are injected by rewriting the consumer's own
156
+ * `src/schema-laws.test.ts` — the one test filename the placement taxonomy
157
+ * whitelists by name. It is deliberately NOT a virtual module: the generated
158
+ * body carries real `import` edges to each schema file, so vitest's
159
+ * related-file walk reaches them. A virtual module breaks that walk (its id
160
+ * has no path on disk), which silently drops every generated law from
161
+ * `stryker --related` runs and reports the survivors as coverage gaps.
162
+ *
125
163
  * @example
126
164
  * ```ts
127
165
  * // vitest.config.ts
@@ -135,27 +173,17 @@ function extendsSchemaClass(superClass) {
135
173
  const inlineSchemaTests = (options) => {
136
174
  let config;
137
175
  return {
138
- name: "@systemfsoftware/inline-schema-tests",
176
+ name: "@systemfsoftware/schema-laws",
139
177
  enforce: "pre",
140
178
  configResolved(c) {
141
179
  config = c;
142
180
  },
143
- resolveId(id) {
144
- return id === "virtual:@systemfsoftware/inline-schema-tests" ? "\0virtual:@systemfsoftware/inline-schema-tests" : void 0;
145
- },
146
- load(id) {
147
- if (id !== "\0virtual:@systemfsoftware/inline-schema-tests") return;
148
- const srcDir = resolve(config.root, options?.dir ?? "src");
149
- const schemas = findExportedSchemas(config.root, srcDir);
150
- if (schemas.length === 0) return "// no schemas found";
151
- return [
152
- `import { ruleOfSchemas } from '@systemfsoftware/effect-schema-law'`,
153
- schemas.map((s) => `import { ${s.name} } from '${s.importPath}'`).join("\n"),
154
- "",
155
- schemas.map((s) => `ruleOfSchemas('${s.name}', ${s.name})`).join("\n")
156
- ].join("\n");
181
+ transform(_code, id) {
182
+ const lawFile = id.split("?")[0];
183
+ if (lawFile === void 0 || !lawFile.endsWith(`/schema-laws.test.ts`)) return;
184
+ return generateSchemaLaws(lawFile, resolve(config.root, options?.dir ?? "src"));
157
185
  }
158
186
  };
159
187
  };
160
188
  //#endregion
161
- export { inlineSchemaTests };
189
+ export { LAW_FILE_BASENAME, generateSchemaLaws, inlineSchemaTests };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@systemfsoftware/effect-schema-vite",
3
3
  "license": "MIT",
4
- "version": "1.3.0",
4
+ "version": "1.5.0",
5
5
  "author": "Ryan Lee <drdgvhbh@gmail.com>",
6
6
  "repository": {
7
7
  "type": "git",
@@ -45,11 +45,12 @@
45
45
  "tsdown": "^0.22.9",
46
46
  "vite": "^7",
47
47
  "vitest": "^4",
48
- "@systemfsoftware/arethetypeswrong-cli": "^1.0.7",
48
+ "@systemfsoftware/effect-gherkin-spec": "^0.5.0",
49
+ "@systemfsoftware/arethetypeswrong-cli": "^1.1.0",
50
+ "@systemfsoftware/effect-schema-law": "^0.6.0",
49
51
  "@systemfsoftware/tsconfig": "^1.2.6",
50
52
  "@systemfsoftware/oxlint-config": "^0.1.0",
51
- "@systemfsoftware/vitest-config": "^0.1.0",
52
- "@systemfsoftware/effect-schema-law": "^0.5.0"
53
+ "@systemfsoftware/vitest-config": "^0.1.0"
53
54
  },
54
55
  "peerDependencies": {
55
56
  "@systemfsoftware/effect-schema-law": "*",