@grayhaven/nerve-react 0.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.
- package/dist/chunk-IBL3BQIP.js +13 -0
- package/dist/chunk-IBL3BQIP.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +77 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx-runtime.d.ts +27 -0
- package/dist/jsx-runtime.js +13 -0
- package/dist/jsx-runtime.js.map +1 -0
- package/package.json +40 -0
- package/src/components.ts +115 -0
- package/src/index.ts +3 -0
- package/src/jsx-runtime.ts +32 -0
- package/test/jsx.test.tsx +59 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// src/jsx-runtime.ts
|
|
2
|
+
var jsx = (type, props) => type(props);
|
|
3
|
+
var jsxs = jsx;
|
|
4
|
+
var jsxDEV = (type, props) => type(props);
|
|
5
|
+
var Fragment = (props) => props.children;
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
jsx,
|
|
9
|
+
jsxs,
|
|
10
|
+
jsxDEV,
|
|
11
|
+
Fragment
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=chunk-IBL3BQIP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/jsx-runtime.ts"],"sourcesContent":["/**\n * Custom JSX runtime (automatic mode): no React, no fiber, no VDOM —\n * `jsx(Component, props)` simply CALLS the component. JSX becomes pure\n * function application over the typed DSL, so authoring style changes\n * and nothing else does.\n */\nexport type JsxComponent<P, R> = (props: P) => R\n\nexport const jsx = <P, R>(type: JsxComponent<P, R>, props: P): R => type(props)\nexport const jsxs = jsx\nexport const jsxDEV = <P, R>(type: JsxComponent<P, R>, props: P): R => type(props)\n\nexport const Fragment = (props: { children?: unknown }): unknown => props.children\n\n// Minimal JSX namespace: components only (no intrinsic lowercase elements —\n// <Harness> not <harness>, keeping every element a typed function).\ndeclare global {\n namespace JSX {\n // Element is intentionally loose (each component returns its own def\n // type); ElementType constrains elements to component FUNCTIONS.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n type Element = any\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n type ElementType = (props: any) => unknown\n interface ElementChildrenAttribute {\n children: unknown\n }\n interface IntrinsicElements {\n [k: string]: never\n }\n }\n}\n"],"mappings":";AAQO,IAAM,MAAM,CAAO,MAA0B,UAAgB,KAAK,KAAK;AACvE,IAAM,OAAO;AACb,IAAM,SAAS,CAAO,MAA0B,UAAgB,KAAK,KAAK;AAE1E,IAAM,WAAW,CAAC,UAA2C,MAAM;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as _grayhaven_nerve from '@grayhaven/nerve';
|
|
2
|
+
import { BranchProps, CableProps, connector, wire, branch, label, splice, cable, ConnectorPart, PinAssignments, PinPartAssignment, HarnessDesign, LabelProps, SpliceProps, WireProps } from '@grayhaven/nerve';
|
|
3
|
+
export { Fragment, jsx, jsxs } from './jsx-runtime.js';
|
|
4
|
+
|
|
5
|
+
type Def = ReturnType<typeof connector | typeof wire | typeof branch | typeof label | typeof splice | typeof cable>;
|
|
6
|
+
type Children = Def | ReadonlyArray<Children> | undefined | null | false;
|
|
7
|
+
declare function Connector(props: {
|
|
8
|
+
ref: string;
|
|
9
|
+
part: ConnectorPart;
|
|
10
|
+
pins: PinAssignments;
|
|
11
|
+
terminals?: PinPartAssignment;
|
|
12
|
+
seals?: PinPartAssignment;
|
|
13
|
+
}): _grayhaven_nerve.ConnectorInstance;
|
|
14
|
+
declare function Wire(props: {
|
|
15
|
+
id: string;
|
|
16
|
+
from: string;
|
|
17
|
+
to: string;
|
|
18
|
+
} & WireProps): _grayhaven_nerve.WireDef;
|
|
19
|
+
declare function Splice(props: {
|
|
20
|
+
id: string;
|
|
21
|
+
} & SpliceProps): _grayhaven_nerve.SpliceDef;
|
|
22
|
+
declare function Cable(props: {
|
|
23
|
+
id: string;
|
|
24
|
+
} & CableProps): _grayhaven_nerve.CableDef;
|
|
25
|
+
declare function Branch(props: {
|
|
26
|
+
id: string;
|
|
27
|
+
} & Omit<BranchProps, "path"> & {
|
|
28
|
+
path: ReadonlyArray<string>;
|
|
29
|
+
}): _grayhaven_nerve.BranchDef;
|
|
30
|
+
declare function Label(props: {
|
|
31
|
+
id: string;
|
|
32
|
+
} & LabelProps): _grayhaven_nerve.LabelDef;
|
|
33
|
+
declare function Harness(props: {
|
|
34
|
+
id: string;
|
|
35
|
+
revision: string;
|
|
36
|
+
units: "mm" | "in";
|
|
37
|
+
children?: Children;
|
|
38
|
+
}): HarnessDesign;
|
|
39
|
+
|
|
40
|
+
export { Branch, Cable, type Children, Connector, Harness, Label, Splice, Wire };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Fragment,
|
|
3
|
+
jsx,
|
|
4
|
+
jsxs
|
|
5
|
+
} from "./chunk-IBL3BQIP.js";
|
|
6
|
+
|
|
7
|
+
// src/components.ts
|
|
8
|
+
import {
|
|
9
|
+
branch as branchFn,
|
|
10
|
+
cable as cableFn,
|
|
11
|
+
connector as connectorFn,
|
|
12
|
+
harness as harnessFn,
|
|
13
|
+
label as labelFn,
|
|
14
|
+
splice as spliceFn,
|
|
15
|
+
wire as wireFn
|
|
16
|
+
} from "@grayhaven/nerve";
|
|
17
|
+
var flatten = (children) => {
|
|
18
|
+
if (children === void 0 || children === null || children === false) return [];
|
|
19
|
+
if (Array.isArray(children)) return children.flatMap(flatten);
|
|
20
|
+
return [children];
|
|
21
|
+
};
|
|
22
|
+
var endpoint = (s) => {
|
|
23
|
+
const dot = s.lastIndexOf(".");
|
|
24
|
+
if (dot === -1) return { kind: "splice-ref", splice: s };
|
|
25
|
+
return { kind: "pin-ref", connector: s.slice(0, dot), pin: s.slice(dot + 1) };
|
|
26
|
+
};
|
|
27
|
+
function Connector(props) {
|
|
28
|
+
const { ref, part, ...rest } = props;
|
|
29
|
+
return connectorFn(ref, part, rest);
|
|
30
|
+
}
|
|
31
|
+
function Wire(props) {
|
|
32
|
+
const { id, from, to, ...rest } = props;
|
|
33
|
+
return wireFn(id, endpoint(from), endpoint(to), rest);
|
|
34
|
+
}
|
|
35
|
+
function Splice(props) {
|
|
36
|
+
const { id, ...rest } = props;
|
|
37
|
+
return spliceFn(id, rest);
|
|
38
|
+
}
|
|
39
|
+
function Cable(props) {
|
|
40
|
+
const { id, ...rest } = props;
|
|
41
|
+
return cableFn(id, rest);
|
|
42
|
+
}
|
|
43
|
+
function Branch(props) {
|
|
44
|
+
const { id, ...rest } = props;
|
|
45
|
+
return branchFn(id, rest);
|
|
46
|
+
}
|
|
47
|
+
function Label(props) {
|
|
48
|
+
const { id, ...rest } = props;
|
|
49
|
+
return labelFn(id, rest);
|
|
50
|
+
}
|
|
51
|
+
function Harness(props) {
|
|
52
|
+
const kids = flatten(props.children);
|
|
53
|
+
const byKind = (kind) => kids.filter((k) => k.kind === kind);
|
|
54
|
+
return harnessFn(props.id, {
|
|
55
|
+
revision: props.revision,
|
|
56
|
+
units: props.units,
|
|
57
|
+
connectors: byKind("connector"),
|
|
58
|
+
wires: byKind("wire"),
|
|
59
|
+
splices: byKind("splice"),
|
|
60
|
+
cables: byKind("cable"),
|
|
61
|
+
branches: byKind("branch"),
|
|
62
|
+
labels: byKind("label")
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
Branch,
|
|
67
|
+
Cable,
|
|
68
|
+
Connector,
|
|
69
|
+
Fragment,
|
|
70
|
+
Harness,
|
|
71
|
+
Label,
|
|
72
|
+
Splice,
|
|
73
|
+
Wire,
|
|
74
|
+
jsx,
|
|
75
|
+
jsxs
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components.ts"],"sourcesContent":["/**\n * JSX components for harness authoring (tscircuit-inspired, experimental).\n * No React: these are plain functions invoked by the custom JSX runtime in\n * jsx-runtime.ts. The output is the SAME typed design objects the function\n * DSL produces — <Harness> compiles to byte-identical HIR (proven in\n * tests), so JSX is purely an authoring-style choice.\n *\n * /** @jsxImportSource @grayhaven/nerve-react */\n * export default (\n * <Harness id=\"h\" revision=\"A\" units=\"mm\">\n * <Connector ref=\"J1\" part={part(\"microfit-2x8\")} pins={{ 1: \"VBAT\" }} />\n * <Wire id=\"W1\" from=\"J1.1\" to=\"M1.1\" gauge=\"20AWG\" color=\"red\" length={420} />\n * </Harness>\n * )\n *\n * Endpoints are strings: \"J1.3\" (connector.pin) or a splice id (\"S1\").\n */\nimport {\n branch as branchFn,\n cable as cableFn,\n connector as connectorFn,\n harness as harnessFn,\n label as labelFn,\n splice as spliceFn,\n wire as wireFn,\n type BranchProps,\n type CableProps,\n type ConnectorPart,\n type HarnessDesign,\n type LabelProps,\n type PinAssignments,\n type PinPartAssignment,\n type SpliceProps,\n type WireProps\n} from \"@grayhaven/nerve\"\n\ntype Def = ReturnType<\n | typeof connectorFn\n | typeof wireFn\n | typeof branchFn\n | typeof labelFn\n | typeof spliceFn\n | typeof cableFn\n>\n\nexport type Children = Def | ReadonlyArray<Children> | undefined | null | false\n\nexport const flatten = (children: Children): Array<Def> => {\n if (children === undefined || children === null || children === false) return []\n if (Array.isArray(children)) return (children as ReadonlyArray<Children>).flatMap(flatten)\n return [children as Def]\n}\n\n/** \"J1.3\" -> pin ref; anything without a dot is a splice id. */\nconst endpoint = (s: string) => {\n const dot = s.lastIndexOf(\".\")\n if (dot === -1) return { kind: \"splice-ref\" as const, splice: s }\n return { kind: \"pin-ref\" as const, connector: s.slice(0, dot), pin: s.slice(dot + 1) }\n}\n\nexport function Connector(props: {\n ref: string\n part: ConnectorPart\n pins: PinAssignments\n terminals?: PinPartAssignment\n seals?: PinPartAssignment\n}) {\n const { ref, part, ...rest } = props\n return connectorFn(ref, part, rest)\n}\n\nexport function Wire(props: { id: string; from: string; to: string } & WireProps) {\n const { id, from, to, ...rest } = props\n return wireFn(id, endpoint(from), endpoint(to), rest)\n}\n\nexport function Splice(props: { id: string } & SpliceProps) {\n const { id, ...rest } = props\n return spliceFn(id, rest)\n}\n\nexport function Cable(props: { id: string } & CableProps) {\n const { id, ...rest } = props\n return cableFn(id, rest)\n}\n\nexport function Branch(props: { id: string } & Omit<BranchProps, \"path\"> & { path: ReadonlyArray<string> }) {\n const { id, ...rest } = props\n return branchFn(id, rest)\n}\n\nexport function Label(props: { id: string } & LabelProps) {\n const { id, ...rest } = props\n return labelFn(id, rest)\n}\n\nexport function Harness(props: {\n id: string\n revision: string\n units: \"mm\" | \"in\"\n children?: Children\n}): HarnessDesign {\n const kids = flatten(props.children)\n const byKind = (kind: Def[\"kind\"]) => kids.filter((k) => k.kind === kind)\n return harnessFn(props.id, {\n revision: props.revision,\n units: props.units,\n connectors: byKind(\"connector\") as never,\n wires: byKind(\"wire\") as never,\n splices: byKind(\"splice\") as never,\n cables: byKind(\"cable\") as never,\n branches: byKind(\"branch\") as never,\n labels: byKind(\"label\") as never\n })\n}\n"],"mappings":";;;;;;;AAiBA;AAAA,EACE,UAAU;AAAA,EACV,SAAS;AAAA,EACT,aAAa;AAAA,EACb,WAAW;AAAA,EACX,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AAAA,OAUH;AAaA,IAAM,UAAU,CAAC,aAAmC;AACzD,MAAI,aAAa,UAAa,aAAa,QAAQ,aAAa,MAAO,QAAO,CAAC;AAC/E,MAAI,MAAM,QAAQ,QAAQ,EAAG,QAAQ,SAAqC,QAAQ,OAAO;AACzF,SAAO,CAAC,QAAe;AACzB;AAGA,IAAM,WAAW,CAAC,MAAc;AAC9B,QAAM,MAAM,EAAE,YAAY,GAAG;AAC7B,MAAI,QAAQ,GAAI,QAAO,EAAE,MAAM,cAAuB,QAAQ,EAAE;AAChE,SAAO,EAAE,MAAM,WAAoB,WAAW,EAAE,MAAM,GAAG,GAAG,GAAG,KAAK,EAAE,MAAM,MAAM,CAAC,EAAE;AACvF;AAEO,SAAS,UAAU,OAMvB;AACD,QAAM,EAAE,KAAK,MAAM,GAAG,KAAK,IAAI;AAC/B,SAAO,YAAY,KAAK,MAAM,IAAI;AACpC;AAEO,SAAS,KAAK,OAA6D;AAChF,QAAM,EAAE,IAAI,MAAM,IAAI,GAAG,KAAK,IAAI;AAClC,SAAO,OAAO,IAAI,SAAS,IAAI,GAAG,SAAS,EAAE,GAAG,IAAI;AACtD;AAEO,SAAS,OAAO,OAAqC;AAC1D,QAAM,EAAE,IAAI,GAAG,KAAK,IAAI;AACxB,SAAO,SAAS,IAAI,IAAI;AAC1B;AAEO,SAAS,MAAM,OAAoC;AACxD,QAAM,EAAE,IAAI,GAAG,KAAK,IAAI;AACxB,SAAO,QAAQ,IAAI,IAAI;AACzB;AAEO,SAAS,OAAO,OAAqF;AAC1G,QAAM,EAAE,IAAI,GAAG,KAAK,IAAI;AACxB,SAAO,SAAS,IAAI,IAAI;AAC1B;AAEO,SAAS,MAAM,OAAoC;AACxD,QAAM,EAAE,IAAI,GAAG,KAAK,IAAI;AACxB,SAAO,QAAQ,IAAI,IAAI;AACzB;AAEO,SAAS,QAAQ,OAKN;AAChB,QAAM,OAAO,QAAQ,MAAM,QAAQ;AACnC,QAAM,SAAS,CAAC,SAAsB,KAAK,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI;AACxE,SAAO,UAAU,MAAM,IAAI;AAAA,IACzB,UAAU,MAAM;AAAA,IAChB,OAAO,MAAM;AAAA,IACb,YAAY,OAAO,WAAW;AAAA,IAC9B,OAAO,OAAO,MAAM;AAAA,IACpB,SAAS,OAAO,QAAQ;AAAA,IACxB,QAAQ,OAAO,OAAO;AAAA,IACtB,UAAU,OAAO,QAAQ;AAAA,IACzB,QAAQ,OAAO,OAAO;AAAA,EACxB,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom JSX runtime (automatic mode): no React, no fiber, no VDOM —
|
|
3
|
+
* `jsx(Component, props)` simply CALLS the component. JSX becomes pure
|
|
4
|
+
* function application over the typed DSL, so authoring style changes
|
|
5
|
+
* and nothing else does.
|
|
6
|
+
*/
|
|
7
|
+
type JsxComponent<P, R> = (props: P) => R;
|
|
8
|
+
declare const jsx: <P, R>(type: JsxComponent<P, R>, props: P) => R;
|
|
9
|
+
declare const jsxs: <P, R>(type: JsxComponent<P, R>, props: P) => R;
|
|
10
|
+
declare const jsxDEV: <P, R>(type: JsxComponent<P, R>, props: P) => R;
|
|
11
|
+
declare const Fragment: (props: {
|
|
12
|
+
children?: unknown;
|
|
13
|
+
}) => unknown;
|
|
14
|
+
declare global {
|
|
15
|
+
namespace JSX {
|
|
16
|
+
type Element = any;
|
|
17
|
+
type ElementType = (props: any) => unknown;
|
|
18
|
+
interface ElementChildrenAttribute {
|
|
19
|
+
children: unknown;
|
|
20
|
+
}
|
|
21
|
+
interface IntrinsicElements {
|
|
22
|
+
[k: string]: never;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { Fragment, type JsxComponent, jsx, jsxDEV, jsxs };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@grayhaven/nerve-react",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "JSX authoring for Grayhaven Nerve harnesses (experimental). No React runtime — a 2KB custom JSX factory over the same typed DSL.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./src/index.ts",
|
|
8
|
+
"./jsx-runtime": "./src/jsx-runtime.ts",
|
|
9
|
+
"./jsx-dev-runtime": "./src/jsx-runtime.ts"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./jsx-runtime": {
|
|
18
|
+
"types": "./dist/jsx-runtime.d.ts",
|
|
19
|
+
"default": "./dist/jsx-runtime.js"
|
|
20
|
+
},
|
|
21
|
+
"./jsx-dev-runtime": {
|
|
22
|
+
"types": "./dist/jsx-runtime.d.ts",
|
|
23
|
+
"default": "./dist/jsx-runtime.js"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsup src/index.ts src/jsx-runtime.ts --format esm --dts --sourcemap --clean",
|
|
29
|
+
"typecheck": "tsc -p . --noEmit"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@grayhaven/nerve": "0.4.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"tsup": "^8.5.0",
|
|
36
|
+
"typescript": "^5.8.3",
|
|
37
|
+
"@grayhaven/nerve-connectors": "0.4.0"
|
|
38
|
+
},
|
|
39
|
+
"license": "Apache-2.0"
|
|
40
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSX components for harness authoring (tscircuit-inspired, experimental).
|
|
3
|
+
* No React: these are plain functions invoked by the custom JSX runtime in
|
|
4
|
+
* jsx-runtime.ts. The output is the SAME typed design objects the function
|
|
5
|
+
* DSL produces — <Harness> compiles to byte-identical HIR (proven in
|
|
6
|
+
* tests), so JSX is purely an authoring-style choice.
|
|
7
|
+
*
|
|
8
|
+
* /** @jsxImportSource @grayhaven/nerve-react */
|
|
9
|
+
* export default (
|
|
10
|
+
* <Harness id="h" revision="A" units="mm">
|
|
11
|
+
* <Connector ref="J1" part={part("microfit-2x8")} pins={{ 1: "VBAT" }} />
|
|
12
|
+
* <Wire id="W1" from="J1.1" to="M1.1" gauge="20AWG" color="red" length={420} />
|
|
13
|
+
* </Harness>
|
|
14
|
+
* )
|
|
15
|
+
*
|
|
16
|
+
* Endpoints are strings: "J1.3" (connector.pin) or a splice id ("S1").
|
|
17
|
+
*/
|
|
18
|
+
import {
|
|
19
|
+
branch as branchFn,
|
|
20
|
+
cable as cableFn,
|
|
21
|
+
connector as connectorFn,
|
|
22
|
+
harness as harnessFn,
|
|
23
|
+
label as labelFn,
|
|
24
|
+
splice as spliceFn,
|
|
25
|
+
wire as wireFn,
|
|
26
|
+
type BranchProps,
|
|
27
|
+
type CableProps,
|
|
28
|
+
type ConnectorPart,
|
|
29
|
+
type HarnessDesign,
|
|
30
|
+
type LabelProps,
|
|
31
|
+
type PinAssignments,
|
|
32
|
+
type PinPartAssignment,
|
|
33
|
+
type SpliceProps,
|
|
34
|
+
type WireProps
|
|
35
|
+
} from "@grayhaven/nerve"
|
|
36
|
+
|
|
37
|
+
type Def = ReturnType<
|
|
38
|
+
| typeof connectorFn
|
|
39
|
+
| typeof wireFn
|
|
40
|
+
| typeof branchFn
|
|
41
|
+
| typeof labelFn
|
|
42
|
+
| typeof spliceFn
|
|
43
|
+
| typeof cableFn
|
|
44
|
+
>
|
|
45
|
+
|
|
46
|
+
export type Children = Def | ReadonlyArray<Children> | undefined | null | false
|
|
47
|
+
|
|
48
|
+
export const flatten = (children: Children): Array<Def> => {
|
|
49
|
+
if (children === undefined || children === null || children === false) return []
|
|
50
|
+
if (Array.isArray(children)) return (children as ReadonlyArray<Children>).flatMap(flatten)
|
|
51
|
+
return [children as Def]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** "J1.3" -> pin ref; anything without a dot is a splice id. */
|
|
55
|
+
const endpoint = (s: string) => {
|
|
56
|
+
const dot = s.lastIndexOf(".")
|
|
57
|
+
if (dot === -1) return { kind: "splice-ref" as const, splice: s }
|
|
58
|
+
return { kind: "pin-ref" as const, connector: s.slice(0, dot), pin: s.slice(dot + 1) }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function Connector(props: {
|
|
62
|
+
ref: string
|
|
63
|
+
part: ConnectorPart
|
|
64
|
+
pins: PinAssignments
|
|
65
|
+
terminals?: PinPartAssignment
|
|
66
|
+
seals?: PinPartAssignment
|
|
67
|
+
}) {
|
|
68
|
+
const { ref, part, ...rest } = props
|
|
69
|
+
return connectorFn(ref, part, rest)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function Wire(props: { id: string; from: string; to: string } & WireProps) {
|
|
73
|
+
const { id, from, to, ...rest } = props
|
|
74
|
+
return wireFn(id, endpoint(from), endpoint(to), rest)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function Splice(props: { id: string } & SpliceProps) {
|
|
78
|
+
const { id, ...rest } = props
|
|
79
|
+
return spliceFn(id, rest)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function Cable(props: { id: string } & CableProps) {
|
|
83
|
+
const { id, ...rest } = props
|
|
84
|
+
return cableFn(id, rest)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function Branch(props: { id: string } & Omit<BranchProps, "path"> & { path: ReadonlyArray<string> }) {
|
|
88
|
+
const { id, ...rest } = props
|
|
89
|
+
return branchFn(id, rest)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function Label(props: { id: string } & LabelProps) {
|
|
93
|
+
const { id, ...rest } = props
|
|
94
|
+
return labelFn(id, rest)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function Harness(props: {
|
|
98
|
+
id: string
|
|
99
|
+
revision: string
|
|
100
|
+
units: "mm" | "in"
|
|
101
|
+
children?: Children
|
|
102
|
+
}): HarnessDesign {
|
|
103
|
+
const kids = flatten(props.children)
|
|
104
|
+
const byKind = (kind: Def["kind"]) => kids.filter((k) => k.kind === kind)
|
|
105
|
+
return harnessFn(props.id, {
|
|
106
|
+
revision: props.revision,
|
|
107
|
+
units: props.units,
|
|
108
|
+
connectors: byKind("connector") as never,
|
|
109
|
+
wires: byKind("wire") as never,
|
|
110
|
+
splices: byKind("splice") as never,
|
|
111
|
+
cables: byKind("cable") as never,
|
|
112
|
+
branches: byKind("branch") as never,
|
|
113
|
+
labels: byKind("label") as never
|
|
114
|
+
})
|
|
115
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom JSX runtime (automatic mode): no React, no fiber, no VDOM —
|
|
3
|
+
* `jsx(Component, props)` simply CALLS the component. JSX becomes pure
|
|
4
|
+
* function application over the typed DSL, so authoring style changes
|
|
5
|
+
* and nothing else does.
|
|
6
|
+
*/
|
|
7
|
+
export type JsxComponent<P, R> = (props: P) => R
|
|
8
|
+
|
|
9
|
+
export const jsx = <P, R>(type: JsxComponent<P, R>, props: P): R => type(props)
|
|
10
|
+
export const jsxs = jsx
|
|
11
|
+
export const jsxDEV = <P, R>(type: JsxComponent<P, R>, props: P): R => type(props)
|
|
12
|
+
|
|
13
|
+
export const Fragment = (props: { children?: unknown }): unknown => props.children
|
|
14
|
+
|
|
15
|
+
// Minimal JSX namespace: components only (no intrinsic lowercase elements —
|
|
16
|
+
// <Harness> not <harness>, keeping every element a typed function).
|
|
17
|
+
declare global {
|
|
18
|
+
namespace JSX {
|
|
19
|
+
// Element is intentionally loose (each component returns its own def
|
|
20
|
+
// type); ElementType constrains elements to component FUNCTIONS.
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
type Element = any
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
+
type ElementType = (props: any) => unknown
|
|
25
|
+
interface ElementChildrenAttribute {
|
|
26
|
+
children: unknown
|
|
27
|
+
}
|
|
28
|
+
interface IntrinsicElements {
|
|
29
|
+
[k: string]: never
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** @jsxImportSource @grayhaven/nerve-react */
|
|
2
|
+
/**
|
|
3
|
+
* The JSX layer is authoring sugar ONLY: the same harness written as JSX
|
|
4
|
+
* and as function calls must compile to byte-identical HIR.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, expect, it } from "vitest"
|
|
7
|
+
import { compileDesign } from "@grayhaven/nerve"
|
|
8
|
+
import { Branch, Connector, Harness, Label, Wire } from "@grayhaven/nerve-react"
|
|
9
|
+
import functionStyle from "../../../examples/motor-controller/src/main.harness.js"
|
|
10
|
+
import { MolexMicroFit } from "@grayhaven/nerve-connectors"
|
|
11
|
+
|
|
12
|
+
const PINS = {
|
|
13
|
+
1: "VBAT_24V", 2: "GND", 3: "CAN_H", 4: "CAN_L",
|
|
14
|
+
5: "ENC_A", 6: "ENC_B", 7: "MOTOR_TEMP", 8: "SHIELD_DRAIN"
|
|
15
|
+
} as const
|
|
16
|
+
|
|
17
|
+
const jsxStyle = (
|
|
18
|
+
<Harness id="motor-controller-harness" revision="A" units="mm">
|
|
19
|
+
<Connector ref="J1" part={MolexMicroFit["43025-0800"]} pins={PINS} />
|
|
20
|
+
<Connector ref="M1" part={MolexMicroFit["43020-0800"]} pins={PINS} />
|
|
21
|
+
<Wire id="W1" from="J1.1" to="M1.1" gauge="20AWG" color="red" length={420} signal="VBAT_24V" />
|
|
22
|
+
<Wire id="W2" from="J1.2" to="M1.2" gauge="20AWG" color="black" length={420} signal="GND" />
|
|
23
|
+
<Wire id="W3" from="J1.3" to="M1.3" gauge="24AWG" color="white" twistGroup="CAN_PAIR" signal="CAN_H" />
|
|
24
|
+
<Wire id="W4" from="J1.4" to="M1.4" gauge="24AWG" color="blue" twistGroup="CAN_PAIR" signal="CAN_L" />
|
|
25
|
+
<Branch id="main" path={["J1", "M1"]} sleeve="braided-pet" nominalLength={420} />
|
|
26
|
+
<Label id="L1" text="MOTOR CTRL A" attachTo="main" offsetFrom="J1" distance={50} />
|
|
27
|
+
</Harness>
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
describe("@grayhaven/nerve-react (experimental JSX authoring)", () => {
|
|
31
|
+
it("compiles JSX to byte-identical HIR vs the function DSL", () => {
|
|
32
|
+
const a = JSON.stringify(compileDesign(jsxStyle).hir, null, 2)
|
|
33
|
+
const b = JSON.stringify(compileDesign(functionStyle).hir, null, 2)
|
|
34
|
+
expect(a).toBe(b)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it("string endpoints parse pins and splices", () => {
|
|
38
|
+
const w = <Wire id="W9" from="J1.12" to="S1" gauge="24AWG" />
|
|
39
|
+
expect(w).toMatchObject({
|
|
40
|
+
from: { kind: "pin-ref", connector: "J1", pin: "12" },
|
|
41
|
+
to: { kind: "splice-ref", splice: "S1" }
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it("nested arrays and conditionals flatten like JSX children should", () => {
|
|
46
|
+
const drops = ["A", "B"].map((s, i) => (
|
|
47
|
+
<Wire id={`W${i}`} from={`J1.${i + 1}`} to={`M1.${i + 1}`} signal={s} gauge="24AWG" />
|
|
48
|
+
))
|
|
49
|
+
const h = (
|
|
50
|
+
<Harness id="t" revision="A" units="mm">
|
|
51
|
+
<Connector ref="J1" part={MolexMicroFit["43025-0800"]} pins={{ 1: "A", 2: "B" }} />
|
|
52
|
+
<Connector ref="M1" part={MolexMicroFit["43020-0800"]} pins={{ 1: "A", 2: "B" }} />
|
|
53
|
+
{drops}
|
|
54
|
+
{false}
|
|
55
|
+
</Harness>
|
|
56
|
+
)
|
|
57
|
+
expect(compileDesign(h).hir.wires).toHaveLength(2)
|
|
58
|
+
})
|
|
59
|
+
})
|