mujoco-react 8.7.0 → 8.8.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/README.md +23 -5
- package/dist/vite.js +29 -2
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
- package/src/vite.ts +35 -2
package/README.md
CHANGED
|
@@ -46,6 +46,7 @@ The plugin writes `src/mujoco-register.gen.d.ts` during dev and build. Commit th
|
|
|
46
46
|
// Auto-generated by mujoco-react. Do not edit.
|
|
47
47
|
|
|
48
48
|
import "mujoco-react";
|
|
49
|
+
import type { RobotResource } from "mujoco-react";
|
|
49
50
|
|
|
50
51
|
declare module "mujoco-react" {
|
|
51
52
|
interface Register {
|
|
@@ -73,10 +74,20 @@ declare module "mujoco-react" {
|
|
|
73
74
|
sensors: "force_sensor" | "torque_sensor";
|
|
74
75
|
bodies: "link0" | "link1" | "hand" | "body" | "fl_hip" | "fl_uleg";
|
|
75
76
|
}
|
|
77
|
+
|
|
78
|
+
export namespace RobotActuators {
|
|
79
|
+
export type franka = RobotResource<"franka", "actuators">;
|
|
80
|
+
export type spot = RobotResource<"spot", "actuators">;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export namespace RobotSites {
|
|
84
|
+
export type franka = RobotResource<"franka", "sites">;
|
|
85
|
+
export type spot = RobotResource<"spot", "sites">;
|
|
86
|
+
}
|
|
76
87
|
}
|
|
77
88
|
```
|
|
78
89
|
|
|
79
|
-
Once generated, hooks like `useCtrl`, `useSensor`, `useBodyState`, and API methods like `setCtrl`, `applyForce`, `getSensorData` accept the global union. For robot-scoped reusable code, use
|
|
90
|
+
Once generated, hooks like `useCtrl`, `useSensor`, `useBodyState`, and API methods like `setCtrl`, `applyForce`, `getSensorData` accept the global union. For robot-scoped reusable code, use generated namespace types such as `RobotActuators.franka`, `RobotSites.franka`, and `RobotBodies.franka`. Generic helpers like `RobotActuators<"franka">` are still available for reusable library code. When no `Register` augmentation is present, names fall back to `string`.
|
|
80
91
|
|
|
81
92
|
Non-Vite projects can generate the same file with:
|
|
82
93
|
|
|
@@ -159,8 +170,8 @@ With generated resource types, reusable controllers can be scoped to one robot.
|
|
|
159
170
|
import { useCtrl, useIkController } from "mujoco-react";
|
|
160
171
|
import type { RobotActuators, RobotSites } from "mujoco-react";
|
|
161
172
|
|
|
162
|
-
const frankaGripper = "gripper"
|
|
163
|
-
const frankaTcp = "tcp"
|
|
173
|
+
const frankaGripper: RobotActuators.franka = "gripper";
|
|
174
|
+
const frankaTcp: RobotSites.franka = "tcp";
|
|
164
175
|
|
|
165
176
|
function FrankaTypedControls() {
|
|
166
177
|
const gripper = useCtrl(frankaGripper);
|
|
@@ -424,15 +435,22 @@ interface SceneConfig {
|
|
|
424
435
|
Load browser-selected MJCF or URDF files directly. Folder uploads preserve `webkitRelativePath`, and flat uploads fall back to matching referenced mesh/texture assets by basename:
|
|
425
436
|
|
|
426
437
|
```tsx
|
|
438
|
+
import { useEffect, useRef } from "react";
|
|
439
|
+
import { useMujoco } from "mujoco-react";
|
|
440
|
+
|
|
427
441
|
function ModelUpload() {
|
|
428
442
|
const sim = useMujoco();
|
|
443
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
444
|
+
|
|
445
|
+
useEffect(() => {
|
|
446
|
+
inputRef.current?.setAttribute("webkitdirectory", "");
|
|
447
|
+
}, []);
|
|
429
448
|
|
|
430
449
|
return (
|
|
431
450
|
<input
|
|
451
|
+
ref={inputRef}
|
|
432
452
|
type="file"
|
|
433
453
|
multiple
|
|
434
|
-
// @ts-expect-error Chromium/WebKit folder uploads
|
|
435
|
-
webkitdirectory=""
|
|
436
454
|
onChange={(event) => {
|
|
437
455
|
if (sim.isReady && event.currentTarget.files) {
|
|
438
456
|
sim.api.loadFromFiles(event.currentTarget.files);
|
package/dist/vite.js
CHANGED
|
@@ -132,10 +132,12 @@ function renderRegister(moduleName, names, models) {
|
|
|
132
132
|
const robots = models.map((model) => ` ${quoteProperty(model.id)}: {
|
|
133
133
|
${renderRobotFields(model.names)}
|
|
134
134
|
};`);
|
|
135
|
+
const namespaceAliases = renderNamespaceAliases(models);
|
|
135
136
|
return `// Auto-generated by mujoco-react. Do not edit.
|
|
136
137
|
// Regenerate by running Vite with the mujocoReact() plugin or \`mujoco-react codegen\`.
|
|
137
138
|
|
|
138
|
-
import '
|
|
139
|
+
import '${moduleName}';
|
|
140
|
+
import type { RobotResource } from '${moduleName}';
|
|
139
141
|
|
|
140
142
|
declare module '${moduleName}' {
|
|
141
143
|
interface Register {
|
|
@@ -144,6 +146,8 @@ ${robots.join("\n")}
|
|
|
144
146
|
};
|
|
145
147
|
${fields.join("\n")}
|
|
146
148
|
}
|
|
149
|
+
|
|
150
|
+
${namespaceAliases}
|
|
147
151
|
}
|
|
148
152
|
`;
|
|
149
153
|
}
|
|
@@ -153,11 +157,34 @@ function renderRobotFields(names) {
|
|
|
153
157
|
function renderUnion(values) {
|
|
154
158
|
return [...values].sort((a, b) => a.localeCompare(b)).map((value) => `'${escapeTs(value)}'`).join(" | ");
|
|
155
159
|
}
|
|
160
|
+
function renderNamespaceAliases(models) {
|
|
161
|
+
const namespaces = {
|
|
162
|
+
actuators: "RobotActuators",
|
|
163
|
+
sensors: "RobotSensors",
|
|
164
|
+
bodies: "RobotBodies",
|
|
165
|
+
joints: "RobotJoints",
|
|
166
|
+
sites: "RobotSites",
|
|
167
|
+
geoms: "RobotGeoms",
|
|
168
|
+
keyframes: "RobotKeyframes"
|
|
169
|
+
};
|
|
170
|
+
const blocks = REGISTER_KEYS.map((key) => {
|
|
171
|
+
const aliases = models.filter((model) => isIdentifier(model.id)).map((model) => ` export type ${model.id} = RobotResource<'${escapeTs(model.id)}', '${key}'>;`);
|
|
172
|
+
if (aliases.length === 0) return "";
|
|
173
|
+
return ` export namespace ${namespaces[key]} {
|
|
174
|
+
${aliases.join("\n")}
|
|
175
|
+
}`;
|
|
176
|
+
}).filter(Boolean).join("\n\n");
|
|
177
|
+
return blocks ? `${blocks}
|
|
178
|
+
` : "";
|
|
179
|
+
}
|
|
156
180
|
function escapeTs(value) {
|
|
157
181
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
158
182
|
}
|
|
159
183
|
function quoteProperty(value) {
|
|
160
|
-
return
|
|
184
|
+
return isIdentifier(value) ? value : `'${escapeTs(value)}'`;
|
|
185
|
+
}
|
|
186
|
+
function isIdentifier(value) {
|
|
187
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);
|
|
161
188
|
}
|
|
162
189
|
function normalizeModels(input) {
|
|
163
190
|
if (typeof input === "string") return [createModelEntry(deriveModelId(input), input)];
|
package/dist/vite.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/vite.ts"],"names":[],"mappings":"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","file":"vite.js","sourcesContent":["/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\n\ntype ViteConfig = { root: string };\ntype ViteServer = {\n watcher: {\n add(paths: string | string[]): void;\n on(event: 'add' | 'change' | 'unlink', listener: (file: string) => void): void;\n };\n};\n\nexport interface MujocoReactPluginOptions {\n /** Entry MJCF/URDF files to scan. Prefer a record for stable per-robot type names. */\n models: ModelInput;\n /** Generated declaration file. Defaults to `src/mujoco-register.gen.d.ts`. */\n generatedRegister?: string;\n /** Module name to augment. Defaults to `mujoco-react`. */\n moduleName?: string;\n /** Disable console output. */\n disableLogging?: boolean;\n}\n\nexport interface MujocoRegisterCodegenOptions {\n models: ModelInput;\n out: string;\n moduleName?: string;\n root?: string;\n}\n\nexport interface MujocoRegisterCodegenResult {\n out: string;\n files: string[];\n counts: Record<RegisterKey, number>;\n}\n\ntype RegisterKey = 'actuators' | 'sensors' | 'bodies' | 'joints' | 'sites' | 'geoms' | 'keyframes';\nexport type ModelInput = string | readonly string[] | Record<string, string>;\n\ninterface ModelEntry {\n id: string;\n file: string;\n names: Record<RegisterKey, Set<string>>;\n}\n\nconst REGISTER_KEYS: RegisterKey[] = ['actuators', 'sensors', 'bodies', 'joints', 'sites', 'geoms', 'keyframes'];\nconst MODEL_EXTENSIONS = new Set(['.xml', '.mjcf', '.urdf']);\n\nfunction createEmptyNames(): Record<RegisterKey, Set<string>> {\n return {\n actuators: new Set(),\n sensors: new Set(),\n bodies: new Set(),\n joints: new Set(),\n sites: new Set(),\n geoms: new Set(),\n keyframes: new Set(),\n };\n}\n\nexport function mujocoReact(options: MujocoReactPluginOptions) {\n const models = normalizeModels(options.models);\n let root = process.cwd();\n let generatedRegister = options.generatedRegister ?? 'src/mujoco-register.gen.d.ts';\n let watchedFiles: string[] = [];\n\n async function generate() {\n const result = await generateMujocoRegister({\n models: options.models,\n out: generatedRegister,\n moduleName: options.moduleName,\n root,\n });\n watchedFiles = result.files;\n if (!options.disableLogging) {\n const total = Object.values(result.counts).reduce((sum, count) => sum + count, 0);\n console.log(`[mujoco-react] generated ${path.relative(root, result.out)} (${total} names)`);\n }\n return result;\n }\n\n return {\n name: 'mujoco-react',\n enforce: 'pre' as const,\n configResolved(config: ViteConfig) {\n root = config.root;\n generatedRegister = path.resolve(root, generatedRegister);\n },\n async buildStart(this: { addWatchFile?: (file: string) => void }) {\n const result = await generate();\n for (const file of result.files) this.addWatchFile?.(file);\n },\n configureServer(server: ViteServer) {\n generate().then((result) => server.watcher.add(result.files)).catch((error: unknown) => {\n console.error('[mujoco-react] register generation failed', error);\n });\n\n server.watcher.on('add', regenerateIfModelFile);\n server.watcher.on('change', regenerateIfModelFile);\n server.watcher.on('unlink', regenerateIfModelFile);\n\n function regenerateIfModelFile(file: string) {\n if (!shouldRegenerate(file, watchedFiles, models, root)) return;\n generate().then((result) => server.watcher.add(result.files)).catch((error: unknown) => {\n console.error('[mujoco-react] register generation failed', error);\n });\n }\n },\n };\n}\n\nexport async function generateMujocoRegister(\n options: MujocoRegisterCodegenOptions\n): Promise<MujocoRegisterCodegenResult> {\n const root = path.resolve(options.root ?? process.cwd());\n const out = path.resolve(root, options.out);\n const moduleName = options.moduleName ?? 'mujoco-react';\n const models = normalizeModels(options.models);\n const names = createEmptyNames();\n const seen = new Set<string>();\n\n for (const model of models) {\n await scanModel(path.resolve(root, model.file), root, seen, model.names);\n mergeNames(names, model.names);\n }\n\n await mkdir(path.dirname(out), { recursive: true });\n await writeFile(out, renderRegister(moduleName, names, models), 'utf8');\n\n return {\n out,\n files: [...seen].sort((a, b) => a.localeCompare(b)),\n counts: Object.fromEntries(REGISTER_KEYS.map((key) => [key, names[key].size])) as Record<RegisterKey, number>,\n };\n}\n\nasync function scanModel(\n filePath: string,\n root: string,\n seen: Set<string>,\n names: Record<RegisterKey, Set<string>>\n) {\n const normalized = path.normalize(filePath);\n if (seen.has(normalized)) return;\n seen.add(normalized);\n\n const xml = await readFile(normalized, 'utf8');\n collectSimpleTagNames(xml, 'body', names.bodies);\n collectSimpleTagNames(xml, 'joint', names.joints);\n collectSimpleTagNames(xml, 'site', names.sites);\n collectSimpleTagNames(xml, 'geom', names.geoms);\n collectSimpleTagNames(xml, 'key', names.keyframes);\n collectSectionNames(xml, 'actuator', names.actuators);\n collectSectionNames(xml, 'sensor', names.sensors);\n\n for (const includePath of collectIncludePaths(xml)) {\n const next = path.resolve(path.dirname(normalized), includePath);\n if (next.startsWith(root)) await scanModel(next, root, seen, names);\n }\n}\n\nfunction collectSimpleTagNames(xml: string, tag: string, target: Set<string>) {\n const pattern = new RegExp(`<\\\\s*${tag}\\\\b([^>]*)>`, 'gi');\n for (const match of xml.matchAll(pattern)) {\n const name = readAttr(match[1], 'name');\n if (name) target.add(name);\n }\n}\n\nfunction collectSectionNames(xml: string, section: string, target: Set<string>) {\n const sectionPattern = new RegExp(`<\\\\s*${section}\\\\b[^>]*>([\\\\s\\\\S]*?)<\\\\s*/\\\\s*${section}\\\\s*>`, 'gi');\n for (const sectionMatch of xml.matchAll(sectionPattern)) {\n const tagPattern = /<\\s*[a-zA-Z0-9_:-]+\\b([^>]*)>/g;\n for (const tagMatch of sectionMatch[1].matchAll(tagPattern)) {\n const name = readAttr(tagMatch[1], 'name');\n if (name) target.add(name);\n }\n }\n}\n\nfunction collectIncludePaths(xml: string): string[] {\n const result: string[] = [];\n const pattern = /<\\s*include\\b([^>]*)>/gi;\n for (const match of xml.matchAll(pattern)) {\n const file = readAttr(match[1], 'file');\n if (file && !file.includes('://') && !file.startsWith('/')) result.push(file);\n }\n return result;\n}\n\nfunction readAttr(attrs: string, attr: string): string | undefined {\n const pattern = new RegExp(`\\\\b${attr}\\\\s*=\\\\s*(['\"])(.*?)\\\\1`, 'i');\n return attrs.match(pattern)?.[2];\n}\n\nfunction renderRegister(\n moduleName: string,\n names: Record<RegisterKey, Set<string>>,\n models: readonly ModelEntry[]\n): string {\n const fields = REGISTER_KEYS\n .filter((key) => names[key].size > 0)\n .map((key) => ` ${key}: ${renderUnion(names[key])};`);\n const robots = models\n .map((model) => ` ${quoteProperty(model.id)}: {\\n${renderRobotFields(model.names)}\\n };`);\n\n return `// Auto-generated by mujoco-react. Do not edit.\n// Regenerate by running Vite with the mujocoReact() plugin or \\`mujoco-react codegen\\`.\n\nimport 'mujoco-react';\n\ndeclare module '${moduleName}' {\n interface Register {\n robots: {\n${robots.join('\\n')}\n };\n${fields.join('\\n')}\n }\n}\n`;\n}\n\nfunction renderRobotFields(names: Record<RegisterKey, Set<string>>): string {\n return REGISTER_KEYS\n .map((key) => ` ${key}: ${names[key].size > 0 ? renderUnion(names[key]) : 'never'};`)\n .join('\\n');\n}\n\nfunction renderUnion(values: Set<string>): string {\n return [...values].sort((a, b) => a.localeCompare(b)).map((value) => `'${escapeTs(value)}'`).join(' | ');\n}\n\nfunction escapeTs(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nfunction quoteProperty(value: string): string {\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value) ? value : `'${escapeTs(value)}'`;\n}\n\nfunction normalizeModels(input: ModelInput): ModelEntry[] {\n if (typeof input === 'string') return [createModelEntry(deriveModelId(input), input)];\n if (Array.isArray(input)) return input.map((file) => createModelEntry(deriveModelId(file), file));\n return Object.entries(input).map(([id, file]) => createModelEntry(sanitizeModelId(id), file));\n}\n\nfunction createModelEntry(id: string, file: string): ModelEntry {\n return { id, file, names: createEmptyNames() };\n}\n\nfunction deriveModelId(file: string): string {\n const normalized = file.replace(/\\\\/g, '/');\n const parts = normalized.split('/').filter(Boolean);\n const filename = parts.at(-1) ?? 'model';\n const parent = parts.length > 1 ? parts.at(-2) : undefined;\n const base = filename.replace(/\\.(xml|mjcf|urdf)$/i, '');\n return sanitizeModelId(parent && ['scene', 'model', 'robot'].includes(base.toLowerCase()) ? parent : base);\n}\n\nfunction sanitizeModelId(value: string): string {\n const sanitized = value.replace(/[^A-Za-z0-9_$]/g, '_').replace(/^[^A-Za-z_$]+/, '');\n return sanitized || 'model';\n}\n\nfunction mergeNames(target: Record<RegisterKey, Set<string>>, source: Record<RegisterKey, Set<string>>) {\n for (const key of REGISTER_KEYS) {\n for (const value of source[key]) target[key].add(value);\n }\n}\n\nfunction shouldRegenerate(file: string, watchedFiles: string[], models: readonly ModelEntry[], root: string): boolean {\n const absolute = path.resolve(file);\n if (watchedFiles.includes(absolute)) return true;\n if (!MODEL_EXTENSIONS.has(path.extname(absolute).toLowerCase())) return false;\n const modelDirs = models.map((model) => path.dirname(path.resolve(root, model.file)));\n return modelDirs.some((dir) => absolute.startsWith(dir));\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/vite.ts"],"names":[],"mappings":"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","file":"vite.js","sourcesContent":["/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\n\ntype ViteConfig = { root: string };\ntype ViteServer = {\n watcher: {\n add(paths: string | string[]): void;\n on(event: 'add' | 'change' | 'unlink', listener: (file: string) => void): void;\n };\n};\n\nexport interface MujocoReactPluginOptions {\n /** Entry MJCF/URDF files to scan. Prefer a record for stable per-robot type names. */\n models: ModelInput;\n /** Generated declaration file. Defaults to `src/mujoco-register.gen.d.ts`. */\n generatedRegister?: string;\n /** Module name to augment. Defaults to `mujoco-react`. */\n moduleName?: string;\n /** Disable console output. */\n disableLogging?: boolean;\n}\n\nexport interface MujocoRegisterCodegenOptions {\n models: ModelInput;\n out: string;\n moduleName?: string;\n root?: string;\n}\n\nexport interface MujocoRegisterCodegenResult {\n out: string;\n files: string[];\n counts: Record<RegisterKey, number>;\n}\n\ntype RegisterKey = 'actuators' | 'sensors' | 'bodies' | 'joints' | 'sites' | 'geoms' | 'keyframes';\nexport type ModelInput = string | readonly string[] | Record<string, string>;\n\ninterface ModelEntry {\n id: string;\n file: string;\n names: Record<RegisterKey, Set<string>>;\n}\n\nconst REGISTER_KEYS: RegisterKey[] = ['actuators', 'sensors', 'bodies', 'joints', 'sites', 'geoms', 'keyframes'];\nconst MODEL_EXTENSIONS = new Set(['.xml', '.mjcf', '.urdf']);\n\nfunction createEmptyNames(): Record<RegisterKey, Set<string>> {\n return {\n actuators: new Set(),\n sensors: new Set(),\n bodies: new Set(),\n joints: new Set(),\n sites: new Set(),\n geoms: new Set(),\n keyframes: new Set(),\n };\n}\n\nexport function mujocoReact(options: MujocoReactPluginOptions) {\n const models = normalizeModels(options.models);\n let root = process.cwd();\n let generatedRegister = options.generatedRegister ?? 'src/mujoco-register.gen.d.ts';\n let watchedFiles: string[] = [];\n\n async function generate() {\n const result = await generateMujocoRegister({\n models: options.models,\n out: generatedRegister,\n moduleName: options.moduleName,\n root,\n });\n watchedFiles = result.files;\n if (!options.disableLogging) {\n const total = Object.values(result.counts).reduce((sum, count) => sum + count, 0);\n console.log(`[mujoco-react] generated ${path.relative(root, result.out)} (${total} names)`);\n }\n return result;\n }\n\n return {\n name: 'mujoco-react',\n enforce: 'pre' as const,\n configResolved(config: ViteConfig) {\n root = config.root;\n generatedRegister = path.resolve(root, generatedRegister);\n },\n async buildStart(this: { addWatchFile?: (file: string) => void }) {\n const result = await generate();\n for (const file of result.files) this.addWatchFile?.(file);\n },\n configureServer(server: ViteServer) {\n generate().then((result) => server.watcher.add(result.files)).catch((error: unknown) => {\n console.error('[mujoco-react] register generation failed', error);\n });\n\n server.watcher.on('add', regenerateIfModelFile);\n server.watcher.on('change', regenerateIfModelFile);\n server.watcher.on('unlink', regenerateIfModelFile);\n\n function regenerateIfModelFile(file: string) {\n if (!shouldRegenerate(file, watchedFiles, models, root)) return;\n generate().then((result) => server.watcher.add(result.files)).catch((error: unknown) => {\n console.error('[mujoco-react] register generation failed', error);\n });\n }\n },\n };\n}\n\nexport async function generateMujocoRegister(\n options: MujocoRegisterCodegenOptions\n): Promise<MujocoRegisterCodegenResult> {\n const root = path.resolve(options.root ?? process.cwd());\n const out = path.resolve(root, options.out);\n const moduleName = options.moduleName ?? 'mujoco-react';\n const models = normalizeModels(options.models);\n const names = createEmptyNames();\n const seen = new Set<string>();\n\n for (const model of models) {\n await scanModel(path.resolve(root, model.file), root, seen, model.names);\n mergeNames(names, model.names);\n }\n\n await mkdir(path.dirname(out), { recursive: true });\n await writeFile(out, renderRegister(moduleName, names, models), 'utf8');\n\n return {\n out,\n files: [...seen].sort((a, b) => a.localeCompare(b)),\n counts: Object.fromEntries(REGISTER_KEYS.map((key) => [key, names[key].size])) as Record<RegisterKey, number>,\n };\n}\n\nasync function scanModel(\n filePath: string,\n root: string,\n seen: Set<string>,\n names: Record<RegisterKey, Set<string>>\n) {\n const normalized = path.normalize(filePath);\n if (seen.has(normalized)) return;\n seen.add(normalized);\n\n const xml = await readFile(normalized, 'utf8');\n collectSimpleTagNames(xml, 'body', names.bodies);\n collectSimpleTagNames(xml, 'joint', names.joints);\n collectSimpleTagNames(xml, 'site', names.sites);\n collectSimpleTagNames(xml, 'geom', names.geoms);\n collectSimpleTagNames(xml, 'key', names.keyframes);\n collectSectionNames(xml, 'actuator', names.actuators);\n collectSectionNames(xml, 'sensor', names.sensors);\n\n for (const includePath of collectIncludePaths(xml)) {\n const next = path.resolve(path.dirname(normalized), includePath);\n if (next.startsWith(root)) await scanModel(next, root, seen, names);\n }\n}\n\nfunction collectSimpleTagNames(xml: string, tag: string, target: Set<string>) {\n const pattern = new RegExp(`<\\\\s*${tag}\\\\b([^>]*)>`, 'gi');\n for (const match of xml.matchAll(pattern)) {\n const name = readAttr(match[1], 'name');\n if (name) target.add(name);\n }\n}\n\nfunction collectSectionNames(xml: string, section: string, target: Set<string>) {\n const sectionPattern = new RegExp(`<\\\\s*${section}\\\\b[^>]*>([\\\\s\\\\S]*?)<\\\\s*/\\\\s*${section}\\\\s*>`, 'gi');\n for (const sectionMatch of xml.matchAll(sectionPattern)) {\n const tagPattern = /<\\s*[a-zA-Z0-9_:-]+\\b([^>]*)>/g;\n for (const tagMatch of sectionMatch[1].matchAll(tagPattern)) {\n const name = readAttr(tagMatch[1], 'name');\n if (name) target.add(name);\n }\n }\n}\n\nfunction collectIncludePaths(xml: string): string[] {\n const result: string[] = [];\n const pattern = /<\\s*include\\b([^>]*)>/gi;\n for (const match of xml.matchAll(pattern)) {\n const file = readAttr(match[1], 'file');\n if (file && !file.includes('://') && !file.startsWith('/')) result.push(file);\n }\n return result;\n}\n\nfunction readAttr(attrs: string, attr: string): string | undefined {\n const pattern = new RegExp(`\\\\b${attr}\\\\s*=\\\\s*(['\"])(.*?)\\\\1`, 'i');\n return attrs.match(pattern)?.[2];\n}\n\nfunction renderRegister(\n moduleName: string,\n names: Record<RegisterKey, Set<string>>,\n models: readonly ModelEntry[]\n): string {\n const fields = REGISTER_KEYS\n .filter((key) => names[key].size > 0)\n .map((key) => ` ${key}: ${renderUnion(names[key])};`);\n const robots = models\n .map((model) => ` ${quoteProperty(model.id)}: {\\n${renderRobotFields(model.names)}\\n };`);\n const namespaceAliases = renderNamespaceAliases(models);\n\n return `// Auto-generated by mujoco-react. Do not edit.\n// Regenerate by running Vite with the mujocoReact() plugin or \\`mujoco-react codegen\\`.\n\nimport '${moduleName}';\nimport type { RobotResource } from '${moduleName}';\n\ndeclare module '${moduleName}' {\n interface Register {\n robots: {\n${robots.join('\\n')}\n };\n${fields.join('\\n')}\n }\n\n${namespaceAliases}\n}\n`;\n}\n\nfunction renderRobotFields(names: Record<RegisterKey, Set<string>>): string {\n return REGISTER_KEYS\n .map((key) => ` ${key}: ${names[key].size > 0 ? renderUnion(names[key]) : 'never'};`)\n .join('\\n');\n}\n\nfunction renderUnion(values: Set<string>): string {\n return [...values].sort((a, b) => a.localeCompare(b)).map((value) => `'${escapeTs(value)}'`).join(' | ');\n}\n\nfunction renderNamespaceAliases(models: readonly ModelEntry[]): string {\n const namespaces: Record<RegisterKey, string> = {\n actuators: 'RobotActuators',\n sensors: 'RobotSensors',\n bodies: 'RobotBodies',\n joints: 'RobotJoints',\n sites: 'RobotSites',\n geoms: 'RobotGeoms',\n keyframes: 'RobotKeyframes',\n };\n\n const blocks = REGISTER_KEYS\n .map((key) => {\n const aliases = models\n .filter((model) => isIdentifier(model.id))\n .map((model) => ` export type ${model.id} = RobotResource<'${escapeTs(model.id)}', '${key}'>;`);\n if (aliases.length === 0) return '';\n return ` export namespace ${namespaces[key]} {\\n${aliases.join('\\n')}\\n }`;\n })\n .filter(Boolean)\n .join('\\n\\n');\n\n return blocks ? `${blocks}\\n` : '';\n}\n\nfunction escapeTs(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nfunction quoteProperty(value: string): string {\n return isIdentifier(value) ? value : `'${escapeTs(value)}'`;\n}\n\nfunction isIdentifier(value: string): boolean {\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);\n}\n\nfunction normalizeModels(input: ModelInput): ModelEntry[] {\n if (typeof input === 'string') return [createModelEntry(deriveModelId(input), input)];\n if (Array.isArray(input)) return input.map((file) => createModelEntry(deriveModelId(file), file));\n return Object.entries(input).map(([id, file]) => createModelEntry(sanitizeModelId(id), file));\n}\n\nfunction createModelEntry(id: string, file: string): ModelEntry {\n return { id, file, names: createEmptyNames() };\n}\n\nfunction deriveModelId(file: string): string {\n const normalized = file.replace(/\\\\/g, '/');\n const parts = normalized.split('/').filter(Boolean);\n const filename = parts.at(-1) ?? 'model';\n const parent = parts.length > 1 ? parts.at(-2) : undefined;\n const base = filename.replace(/\\.(xml|mjcf|urdf)$/i, '');\n return sanitizeModelId(parent && ['scene', 'model', 'robot'].includes(base.toLowerCase()) ? parent : base);\n}\n\nfunction sanitizeModelId(value: string): string {\n const sanitized = value.replace(/[^A-Za-z0-9_$]/g, '_').replace(/^[^A-Za-z_$]+/, '');\n return sanitized || 'model';\n}\n\nfunction mergeNames(target: Record<RegisterKey, Set<string>>, source: Record<RegisterKey, Set<string>>) {\n for (const key of REGISTER_KEYS) {\n for (const value of source[key]) target[key].add(value);\n }\n}\n\nfunction shouldRegenerate(file: string, watchedFiles: string[], models: readonly ModelEntry[], root: string): boolean {\n const absolute = path.resolve(file);\n if (watchedFiles.includes(absolute)) return true;\n if (!MODEL_EXTENSIONS.has(path.extname(absolute).toLowerCase())) return false;\n const modelDirs = models.map((model) => path.dirname(path.resolve(root, model.file)));\n return modelDirs.some((dir) => absolute.startsWith(dir));\n}\n"]}
|
package/package.json
CHANGED
package/src/vite.ts
CHANGED
|
@@ -207,11 +207,13 @@ function renderRegister(
|
|
|
207
207
|
.map((key) => ` ${key}: ${renderUnion(names[key])};`);
|
|
208
208
|
const robots = models
|
|
209
209
|
.map((model) => ` ${quoteProperty(model.id)}: {\n${renderRobotFields(model.names)}\n };`);
|
|
210
|
+
const namespaceAliases = renderNamespaceAliases(models);
|
|
210
211
|
|
|
211
212
|
return `// Auto-generated by mujoco-react. Do not edit.
|
|
212
213
|
// Regenerate by running Vite with the mujocoReact() plugin or \`mujoco-react codegen\`.
|
|
213
214
|
|
|
214
|
-
import '
|
|
215
|
+
import '${moduleName}';
|
|
216
|
+
import type { RobotResource } from '${moduleName}';
|
|
215
217
|
|
|
216
218
|
declare module '${moduleName}' {
|
|
217
219
|
interface Register {
|
|
@@ -220,6 +222,8 @@ ${robots.join('\n')}
|
|
|
220
222
|
};
|
|
221
223
|
${fields.join('\n')}
|
|
222
224
|
}
|
|
225
|
+
|
|
226
|
+
${namespaceAliases}
|
|
223
227
|
}
|
|
224
228
|
`;
|
|
225
229
|
}
|
|
@@ -234,12 +238,41 @@ function renderUnion(values: Set<string>): string {
|
|
|
234
238
|
return [...values].sort((a, b) => a.localeCompare(b)).map((value) => `'${escapeTs(value)}'`).join(' | ');
|
|
235
239
|
}
|
|
236
240
|
|
|
241
|
+
function renderNamespaceAliases(models: readonly ModelEntry[]): string {
|
|
242
|
+
const namespaces: Record<RegisterKey, string> = {
|
|
243
|
+
actuators: 'RobotActuators',
|
|
244
|
+
sensors: 'RobotSensors',
|
|
245
|
+
bodies: 'RobotBodies',
|
|
246
|
+
joints: 'RobotJoints',
|
|
247
|
+
sites: 'RobotSites',
|
|
248
|
+
geoms: 'RobotGeoms',
|
|
249
|
+
keyframes: 'RobotKeyframes',
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const blocks = REGISTER_KEYS
|
|
253
|
+
.map((key) => {
|
|
254
|
+
const aliases = models
|
|
255
|
+
.filter((model) => isIdentifier(model.id))
|
|
256
|
+
.map((model) => ` export type ${model.id} = RobotResource<'${escapeTs(model.id)}', '${key}'>;`);
|
|
257
|
+
if (aliases.length === 0) return '';
|
|
258
|
+
return ` export namespace ${namespaces[key]} {\n${aliases.join('\n')}\n }`;
|
|
259
|
+
})
|
|
260
|
+
.filter(Boolean)
|
|
261
|
+
.join('\n\n');
|
|
262
|
+
|
|
263
|
+
return blocks ? `${blocks}\n` : '';
|
|
264
|
+
}
|
|
265
|
+
|
|
237
266
|
function escapeTs(value: string): string {
|
|
238
267
|
return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
239
268
|
}
|
|
240
269
|
|
|
241
270
|
function quoteProperty(value: string): string {
|
|
242
|
-
return
|
|
271
|
+
return isIdentifier(value) ? value : `'${escapeTs(value)}'`;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function isIdentifier(value: string): boolean {
|
|
275
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);
|
|
243
276
|
}
|
|
244
277
|
|
|
245
278
|
function normalizeModels(input: ModelInput): ModelEntry[] {
|