@k8ordo/form 0.1.0 → 0.1.1

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.
package/README.md CHANGED
@@ -96,6 +96,12 @@ async per-field checks, components that render no input of their own, and what
96
96
  the package guarantees (nothing dropped in silence, native validation kept
97
97
  without JavaScript, secrets never echoed).
98
98
 
99
+ A check HTML cannot express — a `refine`, a regex the `pattern` attribute
100
+ would reinterpret — is returned in `dropped` (typed as `DroppedCheck`, exported
101
+ from both entries) and, outside production, logged once per schema with
102
+ `console.warn`, so it is seen without anyone remembering to read it. It still
103
+ runs on the server.
104
+
99
105
  ## AI Agent Documentation
100
106
 
101
107
  The docs ship **inside the package**, so an agent always reads the exact
@@ -21,6 +21,30 @@ const patternFlags = (schema, source) => {
21
21
  /** What a `datetime-local` control actually submits: no seconds, no zone. */
22
22
  const DATETIME_LOCAL_PROBE = "2000-01-01T00:00";
23
23
  /**
24
+ * Schemas whose `dropped` list has already been reported. `formFields` is not
25
+ * memoized, so a schema derived in every request would otherwise warn on
26
+ * every request; keyed by the schema object, an HMR re-evaluation still gets
27
+ * its warning back, because it is a new object.
28
+ */
29
+ const warned = /* @__PURE__ */ new WeakSet();
30
+ /**
31
+ * `dropped` is returned, but a return value is only seen by whoever reads
32
+ * it. Outside production the list is also written to the console, once per
33
+ * schema, so the checks the browser will never run are noticed without
34
+ * anyone remembering to look.
35
+ */
36
+ const warnDropped = (schema, dropped) => {
37
+ if (process.env.NODE_ENV === "production") return;
38
+ if (dropped.length === 0 || warned.has(schema)) return;
39
+ warned.add(schema);
40
+ const lines = dropped.map(({ field, reason }) => ` - ${field}: ${reason}`);
41
+ console.warn([
42
+ "[@k8ordo/form] クライアントでは検査されないチェックがあります(サーバーでは検査されます)。",
43
+ ...lines,
44
+ " ブラウザ側でも検査するには、formFields の戻り値 dropped を確認してください。"
45
+ ].join("\n"));
46
+ };
47
+ /**
24
48
  * Derive input attributes and messages from one zod object schema.
25
49
  *
26
50
  * Call this on the server — in a Server Component or at module scope. The
@@ -72,6 +96,7 @@ const formFields = (input) => {
72
96
  field: "(schema)",
73
97
  reason: `${String(objectChecks)}件のオブジェクト階層のチェック(refine など)は HTML の制約属性に落ちないため、クライアントでは検査されません`
74
98
  });
99
+ warnDropped(schema, dropped);
75
100
  return {
76
101
  fields,
77
102
  arrays,
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AsyncCheck, useAsyncCheck } from "./async-check.mjs";
2
2
  import { Rule } from "./rules/rules.mjs";
3
- import { DerivedArray, DerivedField, FieldInput, FormFields, FormState, ValidityFlag } from "./types.mjs";
3
+ import { DerivedArray, DerivedField, DroppedCheck, FieldInput, FormFields, FormState, ValidityFlag } from "./types.mjs";
4
4
  import { HiddenValue } from "./hidden-value.mjs";
5
5
  import { ArrayView, FieldView, RowView, UseFormReturn, useForm } from "./use-form.mjs";
6
- export { type ArrayView, type AsyncCheck, type DerivedArray, type DerivedField, type FieldInput, type FieldView, type FormFields, type FormState, HiddenValue, type RowView, type Rule, type UseFormReturn, type ValidityFlag, useAsyncCheck, useForm };
6
+ export { type ArrayView, type AsyncCheck, type DerivedArray, type DerivedField, type DroppedCheck, type FieldInput, type FieldView, type FormFields, type FormState, HiddenValue, type RowView, type Rule, type UseFormReturn, type ValidityFlag, useAsyncCheck, useForm };
package/docs/GUIDE.md CHANGED
@@ -121,7 +121,8 @@ cross-field rules, an exclusive bound on a float, a regex whose flags or
121
121
  anchoring the `pattern` attribute would silently reinterpret, a
122
122
  `z.iso.datetime()` no `datetime-local` control can ever satisfy — are returned
123
123
  in `dropped`. They still run on the server; you are told they do not run on
124
- the client.
124
+ the client. Outside production `formFields` also logs the list once per schema
125
+ with `console.warn`, so it is seen without anyone remembering to read it.
125
126
 
126
127
  **A schema this package cannot express fails at derive time.** `z.record`,
127
128
  tuples, a repeat nested inside a repeat, nullable objects, keys containing
package/docs/llms.txt CHANGED
@@ -23,10 +23,15 @@ When installed via npm, these docs live under `node_modules/@k8ordo/form/docs/`.
23
23
  `field(path)` accessor giving input attributes, the current error, and
24
24
  `invalid` / `required`, an `array(path)` accessor for repeated rows, and
25
25
  `isDirty`. Also `useAsyncCheck` for server-answered per-field checks and
26
- `HiddenValue` for components that render no input of their own.
26
+ `HiddenValue` for components that render no input of their own. The types
27
+ of the `formFields` result (`FormFields`, `DerivedField`, `DerivedArray`,
28
+ `DroppedCheck`) are exported here as well, since the result crosses to the
29
+ client as a prop.
27
30
  - `@k8ordo/form/server` — server. `formFields(schema)` derives serializable
28
- fields plus a `dropped` list of checks HTML cannot express, and throws on a
29
- schema no form can represent; `parseForm(schema, formData)` validates a
31
+ fields plus a `dropped` list of checks HTML cannot express (outside
32
+ production the list is also logged once per schema with `console.warn`),
33
+ and throws on a schema no form can represent;
34
+ `parseForm(schema, formData)` validates a
30
35
  submission and returns typed data or per-field errors with the submitted
31
36
  values. `defineForm(schema, rules)` attaches cross-field rules (`sameAs`,
32
37
  `minChecked`, `requiredWhen`) typed against the schema's paths.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k8ordo/form",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Derive HTML constraint attributes and per-field errors from one zod schema. Works without JavaScript.",
5
5
  "keywords": [
6
6
  "constraint-validation",
@@ -11,6 +11,9 @@
11
11
  "zod"
12
12
  ],
13
13
  "homepage": "https://ordo.k8o.me",
14
+ "bugs": {
15
+ "url": "https://github.com/k35o/k8ordo/issues"
16
+ },
14
17
  "license": "MIT",
15
18
  "author": "k8o <kosakanoki@gmail.com>",
16
19
  "repository": {
@@ -39,9 +42,11 @@
39
42
  "registry": "https://registry.npmjs.org"
40
43
  },
41
44
  "devDependencies": {
45
+ "@arethetypeswrong/cli": "0.18.5",
42
46
  "@types/react": "19.2.18",
43
47
  "@vitejs/plugin-react": "6.0.5",
44
48
  "@vitest/browser-playwright": "4.1.10",
49
+ "publint": "0.3.23",
45
50
  "react": "19.2.8",
46
51
  "react-dom": "19.2.8",
47
52
  "typescript": "7.0.2",
@@ -71,6 +76,7 @@
71
76
  "test": "vp test",
72
77
  "typecheck": "tsc --noEmit",
73
78
  "check": "vp check",
74
- "check:write": "vp check --fix"
79
+ "check:write": "vp check --fix",
80
+ "check:package": "publint && attw --pack . --profile esm-only"
75
81
  }
76
82
  }