mujoco-react 8.7.0 → 8.9.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 +89 -22
- package/bin/mujoco-react.mjs +2 -2
- package/dist/index.d.ts +23 -1
- package/dist/index.js +58 -1
- package/dist/index.js.map +1 -1
- package/dist/vite.d.ts +2 -1
- package/dist/vite.js +106 -7
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +12 -7
- package/src/types.ts +80 -0
- package/src/vite.ts +115 -8
package/dist/vite.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ type ViteServer = {
|
|
|
14
14
|
interface MujocoReactPluginOptions {
|
|
15
15
|
/** Entry MJCF/URDF files to scan. Prefer a record for stable per-robot type names. */
|
|
16
16
|
models: ModelInput;
|
|
17
|
-
/** Generated
|
|
17
|
+
/** Generated resource module. Defaults to `src/mujoco-register.gen.ts`. */
|
|
18
18
|
generatedRegister?: string;
|
|
19
19
|
/** Module name to augment. Defaults to `mujoco-react`. */
|
|
20
20
|
moduleName?: string;
|
|
@@ -38,6 +38,7 @@ declare function mujocoReact(options: MujocoReactPluginOptions): {
|
|
|
38
38
|
name: string;
|
|
39
39
|
enforce: "pre";
|
|
40
40
|
configResolved(config: ViteConfig): void;
|
|
41
|
+
transform(code: string, id: string): string | undefined;
|
|
41
42
|
buildStart(this: {
|
|
42
43
|
addWatchFile?: (file: string) => void;
|
|
43
44
|
}): Promise<void>;
|
package/dist/vite.js
CHANGED
|
@@ -18,7 +18,7 @@ function createEmptyNames() {
|
|
|
18
18
|
function mujocoReact(options) {
|
|
19
19
|
const models = normalizeModels(options.models);
|
|
20
20
|
let root = process.cwd();
|
|
21
|
-
let generatedRegister = options.generatedRegister ?? "src/mujoco-register.gen.
|
|
21
|
+
let generatedRegister = options.generatedRegister ?? "src/mujoco-register.gen.ts";
|
|
22
22
|
let watchedFiles = [];
|
|
23
23
|
async function generate() {
|
|
24
24
|
const result = await generateMujocoRegister({
|
|
@@ -41,6 +41,11 @@ function mujocoReact(options) {
|
|
|
41
41
|
root = config.root;
|
|
42
42
|
generatedRegister = path.resolve(root, generatedRegister);
|
|
43
43
|
},
|
|
44
|
+
transform(code, id) {
|
|
45
|
+
if (!shouldInjectRegisterImport(id, root, generatedRegister)) return;
|
|
46
|
+
return `${renderGeneratedImport(id, generatedRegister)}
|
|
47
|
+
${code}`;
|
|
48
|
+
},
|
|
44
49
|
async buildStart() {
|
|
45
50
|
const result = await generate();
|
|
46
51
|
for (const file of result.files) this.addWatchFile?.(file);
|
|
@@ -68,12 +73,13 @@ async function generateMujocoRegister(options) {
|
|
|
68
73
|
const models = normalizeModels(options.models);
|
|
69
74
|
const names = createEmptyNames();
|
|
70
75
|
const seen = /* @__PURE__ */ new Set();
|
|
76
|
+
const declarationsOnly = out.endsWith(".d.ts");
|
|
71
77
|
for (const model of models) {
|
|
72
78
|
await scanModel(path.resolve(root, model.file), root, seen, model.names);
|
|
73
79
|
mergeNames(names, model.names);
|
|
74
80
|
}
|
|
75
81
|
await mkdir(path.dirname(out), { recursive: true });
|
|
76
|
-
await writeFile(out, renderRegister(moduleName, names, models), "utf8");
|
|
82
|
+
await writeFile(out, renderRegister(moduleName, names, models, declarationsOnly), "utf8");
|
|
77
83
|
return {
|
|
78
84
|
out,
|
|
79
85
|
files: [...seen].sort((a, b) => a.localeCompare(b)),
|
|
@@ -127,37 +133,130 @@ function readAttr(attrs, attr) {
|
|
|
127
133
|
const pattern = new RegExp(`\\b${attr}\\s*=\\s*(['"])(.*?)\\1`, "i");
|
|
128
134
|
return attrs.match(pattern)?.[2];
|
|
129
135
|
}
|
|
130
|
-
function renderRegister(moduleName, names, models) {
|
|
136
|
+
function renderRegister(moduleName, names, models, declarationsOnly) {
|
|
131
137
|
const fields = REGISTER_KEYS.filter((key) => names[key].size > 0).map((key) => ` ${key}: ${renderUnion(names[key])};`);
|
|
132
138
|
const robots = models.map((model) => ` ${quoteProperty(model.id)}: {
|
|
133
139
|
${renderRobotFields(model.names)}
|
|
134
140
|
};`);
|
|
141
|
+
const namespaceAliases = renderNamespaceAliases(models);
|
|
142
|
+
const registerImport = declarationsOnly ? "" : `import { registerRobotResources } from '${moduleName}';
|
|
143
|
+
`;
|
|
144
|
+
const resources = declarationsOnly ? "" : `${renderResourceTypes(models)}
|
|
145
|
+
|
|
146
|
+
${renderResourceConstants(models)}
|
|
147
|
+
|
|
148
|
+
registerRobotResources(generatedRobotResources);
|
|
149
|
+
|
|
150
|
+
`;
|
|
135
151
|
return `// Auto-generated by mujoco-react. Do not edit.
|
|
136
152
|
// Regenerate by running Vite with the mujocoReact() plugin or \`mujoco-react codegen\`.
|
|
137
153
|
|
|
138
|
-
import '
|
|
154
|
+
${registerImport}import type { RobotResource } from '${moduleName}';
|
|
139
155
|
|
|
140
|
-
declare module '${moduleName}' {
|
|
156
|
+
${resources}declare module '${moduleName}' {
|
|
141
157
|
interface Register {
|
|
142
158
|
robots: {
|
|
143
159
|
${robots.join("\n")}
|
|
144
160
|
};
|
|
145
161
|
${fields.join("\n")}
|
|
146
162
|
}
|
|
163
|
+
|
|
164
|
+
${namespaceAliases}
|
|
147
165
|
}
|
|
148
166
|
`;
|
|
149
167
|
}
|
|
168
|
+
function renderResourceTypes(models) {
|
|
169
|
+
const modelTypes = models.map((model) => ` readonly ${quoteProperty(model.id)}: {
|
|
170
|
+
${renderResourceTypeFields(model.names)}
|
|
171
|
+
};`).join("\n");
|
|
172
|
+
return `type GeneratedRobotResources = {
|
|
173
|
+
${modelTypes}
|
|
174
|
+
};`;
|
|
175
|
+
}
|
|
176
|
+
function renderResourceTypeFields(names) {
|
|
177
|
+
return REGISTER_KEYS.map((key) => ` readonly ${key}: ${renderResourceObjectType(names[key])};`).join("\n");
|
|
178
|
+
}
|
|
179
|
+
function renderResourceObjectType(values) {
|
|
180
|
+
const entries = sortedValues(values).map((value) => ` readonly ${quoteProperty(value)}: '${escapeTs(value)}';`);
|
|
181
|
+
return entries.length > 0 ? `{
|
|
182
|
+
${entries.join("\n")}
|
|
183
|
+
}` : "{}";
|
|
184
|
+
}
|
|
185
|
+
function renderResourceConstants(models) {
|
|
186
|
+
const entries = models.map((model) => ` ${quoteProperty(model.id)}: {
|
|
187
|
+
${renderResourceConstantFields(model.names)}
|
|
188
|
+
},`).join("\n");
|
|
189
|
+
return `const generatedRobotResources: GeneratedRobotResources = {
|
|
190
|
+
${entries}
|
|
191
|
+
};`;
|
|
192
|
+
}
|
|
193
|
+
function renderResourceConstantFields(names) {
|
|
194
|
+
return REGISTER_KEYS.map((key) => ` ${key}: ${renderResourceObject(names[key])},`).join("\n");
|
|
195
|
+
}
|
|
196
|
+
function renderResourceObject(values) {
|
|
197
|
+
const entries = sortedValues(values).map((value) => ` ${quoteProperty(value)}: '${escapeTs(value)}',`);
|
|
198
|
+
return entries.length > 0 ? `{
|
|
199
|
+
${entries.join("\n")}
|
|
200
|
+
}` : "{}";
|
|
201
|
+
}
|
|
150
202
|
function renderRobotFields(names) {
|
|
151
203
|
return REGISTER_KEYS.map((key) => ` ${key}: ${names[key].size > 0 ? renderUnion(names[key]) : "never"};`).join("\n");
|
|
152
204
|
}
|
|
153
205
|
function renderUnion(values) {
|
|
154
|
-
return
|
|
206
|
+
return sortedValues(values).map((value) => `'${escapeTs(value)}'`).join(" | ");
|
|
207
|
+
}
|
|
208
|
+
function renderNamespaceAliases(models) {
|
|
209
|
+
const namespaces = {
|
|
210
|
+
actuators: "RobotActuators",
|
|
211
|
+
sensors: "RobotSensors",
|
|
212
|
+
bodies: "RobotBodies",
|
|
213
|
+
joints: "RobotJoints",
|
|
214
|
+
sites: "RobotSites",
|
|
215
|
+
geoms: "RobotGeoms",
|
|
216
|
+
keyframes: "RobotKeyframes"
|
|
217
|
+
};
|
|
218
|
+
const blocks = REGISTER_KEYS.map((key) => {
|
|
219
|
+
const aliases = models.filter((model) => isIdentifier(model.id)).map((model) => ` export type ${model.id} = RobotResource<'${escapeTs(model.id)}', '${key}'>;`);
|
|
220
|
+
if (aliases.length === 0) return "";
|
|
221
|
+
return ` export namespace ${namespaces[key]} {
|
|
222
|
+
${aliases.join("\n")}
|
|
223
|
+
}`;
|
|
224
|
+
}).filter(Boolean).join("\n\n");
|
|
225
|
+
return blocks ? `${blocks}
|
|
226
|
+
` : "";
|
|
155
227
|
}
|
|
156
228
|
function escapeTs(value) {
|
|
157
229
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
158
230
|
}
|
|
231
|
+
function sortedValues(values) {
|
|
232
|
+
return [...values].sort((a, b) => a.localeCompare(b));
|
|
233
|
+
}
|
|
159
234
|
function quoteProperty(value) {
|
|
160
|
-
return
|
|
235
|
+
return isIdentifier(value) ? value : `'${escapeTs(value)}'`;
|
|
236
|
+
}
|
|
237
|
+
function isIdentifier(value) {
|
|
238
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);
|
|
239
|
+
}
|
|
240
|
+
function toPosixPath(value) {
|
|
241
|
+
return value.split(path.sep).join("/");
|
|
242
|
+
}
|
|
243
|
+
function shouldInjectRegisterImport(id, root, generatedRegister) {
|
|
244
|
+
if (generatedRegister.endsWith(".d.ts")) return false;
|
|
245
|
+
const file = stripQuery(id);
|
|
246
|
+
if (!/\.[cm]?[jt]sx?$/.test(file)) return false;
|
|
247
|
+
if (file.includes(`${path.sep}node_modules${path.sep}`)) return false;
|
|
248
|
+
const absolute = path.resolve(file);
|
|
249
|
+
if (absolute === generatedRegister) return false;
|
|
250
|
+
return absolute.startsWith(root);
|
|
251
|
+
}
|
|
252
|
+
function renderGeneratedImport(id, generatedRegister) {
|
|
253
|
+
const fromDir = path.dirname(stripQuery(id));
|
|
254
|
+
let relative = toPosixPath(path.relative(fromDir, generatedRegister));
|
|
255
|
+
if (!relative.startsWith(".")) relative = `./${relative}`;
|
|
256
|
+
return `import '${relative}';`;
|
|
257
|
+
}
|
|
258
|
+
function stripQuery(id) {
|
|
259
|
+
return id.split("?")[0];
|
|
161
260
|
}
|
|
162
261
|
function normalizeModels(input) {
|
|
163
262
|
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 resource module. Defaults to `src/mujoco-register.gen.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.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 transform(code: string, id: string) {\n if (!shouldInjectRegisterImport(id, root, generatedRegister)) return;\n return `${renderGeneratedImport(id, generatedRegister)}\\n${code}`;\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 const declarationsOnly = out.endsWith('.d.ts');\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, declarationsOnly), '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 declarationsOnly: boolean\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 const registerImport = declarationsOnly ? '' : `import { registerRobotResources } from '${moduleName}';\\n`;\n const resources = declarationsOnly ? '' : `${renderResourceTypes(models)}\\n\\n${renderResourceConstants(models)}\\n\\nregisterRobotResources(generatedRobotResources);\\n\\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\n${registerImport}import type { RobotResource } from '${moduleName}';\n\n${resources}declare 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 renderResourceTypes(models: readonly ModelEntry[]): string {\n const modelTypes = models\n .map((model) => ` readonly ${quoteProperty(model.id)}: {\\n${renderResourceTypeFields(model.names)}\\n };`)\n .join('\\n');\n return `type GeneratedRobotResources = {\\n${modelTypes}\\n};`;\n}\n\nfunction renderResourceTypeFields(names: Record<RegisterKey, Set<string>>): string {\n return REGISTER_KEYS\n .map((key) => ` readonly ${key}: ${renderResourceObjectType(names[key])};`)\n .join('\\n');\n}\n\nfunction renderResourceObjectType(values: Set<string>): string {\n const entries = sortedValues(values)\n .map((value) => ` readonly ${quoteProperty(value)}: '${escapeTs(value)}';`);\n return entries.length > 0 ? `{\\n${entries.join('\\n')}\\n }` : '{}';\n}\n\nfunction renderResourceConstants(models: readonly ModelEntry[]): string {\n const entries = models\n .map((model) => ` ${quoteProperty(model.id)}: {\\n${renderResourceConstantFields(model.names)}\\n },`)\n .join('\\n');\n return `const generatedRobotResources: GeneratedRobotResources = {\\n${entries}\\n};`;\n}\n\nfunction renderResourceConstantFields(names: Record<RegisterKey, Set<string>>): string {\n return REGISTER_KEYS\n .map((key) => ` ${key}: ${renderResourceObject(names[key])},`)\n .join('\\n');\n}\n\nfunction renderResourceObject(values: Set<string>): string {\n const entries = sortedValues(values)\n .map((value) => ` ${quoteProperty(value)}: '${escapeTs(value)}',`);\n return entries.length > 0 ? `{\\n${entries.join('\\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 sortedValues(values).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 sortedValues(values: Set<string>): string[] {\n return [...values].sort((a, b) => a.localeCompare(b));\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 toPosixPath(value: string): string {\n return value.split(path.sep).join('/');\n}\n\nfunction shouldInjectRegisterImport(id: string, root: string, generatedRegister: string): boolean {\n if (generatedRegister.endsWith('.d.ts')) return false;\n const file = stripQuery(id);\n if (!/\\.[cm]?[jt]sx?$/.test(file)) return false;\n if (file.includes(`${path.sep}node_modules${path.sep}`)) return false;\n const absolute = path.resolve(file);\n if (absolute === generatedRegister) return false;\n return absolute.startsWith(root);\n}\n\nfunction renderGeneratedImport(id: string, generatedRegister: string): string {\n const fromDir = path.dirname(stripQuery(id));\n let relative = toPosixPath(path.relative(fromDir, generatedRegister));\n if (!relative.startsWith('.')) relative = `./${relative}`;\n return `import '${relative}';`;\n}\n\nfunction stripQuery(id: string): string {\n return id.split('?')[0];\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/index.ts
CHANGED
|
@@ -145,13 +145,6 @@ export type {
|
|
|
145
145
|
RegisteredRobotMap,
|
|
146
146
|
RobotResource,
|
|
147
147
|
Robots,
|
|
148
|
-
RobotActuators,
|
|
149
|
-
RobotSensors,
|
|
150
|
-
RobotBodies,
|
|
151
|
-
RobotJoints,
|
|
152
|
-
RobotSites,
|
|
153
|
-
RobotGeoms,
|
|
154
|
-
RobotKeyframes,
|
|
155
148
|
Actuators,
|
|
156
149
|
Sensors,
|
|
157
150
|
Bodies,
|
|
@@ -161,6 +154,18 @@ export type {
|
|
|
161
154
|
Keyframes,
|
|
162
155
|
} from './types';
|
|
163
156
|
|
|
157
|
+
export {
|
|
158
|
+
registerRobotResources,
|
|
159
|
+
RobotResources,
|
|
160
|
+
RobotActuators,
|
|
161
|
+
RobotSensors,
|
|
162
|
+
RobotBodies,
|
|
163
|
+
RobotJoints,
|
|
164
|
+
RobotSites,
|
|
165
|
+
RobotGeoms,
|
|
166
|
+
RobotKeyframes,
|
|
167
|
+
} from './types';
|
|
168
|
+
|
|
164
169
|
// Re-export MuJoCo types for convenience
|
|
165
170
|
export type { MujocoModule, MujocoModel, MujocoData, MujocoContact, MujocoContactArray } from './types';
|
|
166
171
|
export { getContact } from './types';
|
package/src/types.ts
CHANGED
|
@@ -55,6 +55,86 @@ export type RobotSites<TRobot extends string> = RobotResource<TRobot, 'sites'>;
|
|
|
55
55
|
export type RobotGeoms<TRobot extends string> = RobotResource<TRobot, 'geoms'>;
|
|
56
56
|
export type RobotKeyframes<TRobot extends string> = RobotResource<TRobot, 'keyframes'>;
|
|
57
57
|
|
|
58
|
+
export type RegisterResourceKey = 'actuators' | 'sensors' | 'bodies' | 'joints' | 'sites' | 'geoms' | 'keyframes';
|
|
59
|
+
export type RobotResourceObject<TRobot extends string, TKey extends RegisterResourceKey> =
|
|
60
|
+
string extends RobotResource<TRobot, TKey>
|
|
61
|
+
? Record<string, string>
|
|
62
|
+
: { readonly [K in RobotResource<TRobot, TKey>]: K };
|
|
63
|
+
export type RobotResourceCategory<TKey extends RegisterResourceKey> =
|
|
64
|
+
string extends Robots
|
|
65
|
+
? Record<string, Record<string, string>>
|
|
66
|
+
: { readonly [TRobot in Robots]: RobotResourceObject<TRobot, TKey> };
|
|
67
|
+
export type RobotResourceRegistry =
|
|
68
|
+
string extends Robots
|
|
69
|
+
? Record<string, Record<RegisterResourceKey, Record<string, string>>>
|
|
70
|
+
: { readonly [TRobot in Robots]: { readonly [TKey in RegisterResourceKey]: RobotResourceObject<TRobot, TKey> } };
|
|
71
|
+
|
|
72
|
+
type RuntimeRobotResources = Record<string, Record<RegisterResourceKey, Record<string, string>>>;
|
|
73
|
+
type RuntimeRobotResourceRegistration = Readonly<Record<string, Readonly<Record<RegisterResourceKey, Readonly<Record<string, string>>>>>>;
|
|
74
|
+
|
|
75
|
+
const runtimeRobotResources: RuntimeRobotResources = {};
|
|
76
|
+
const REGISTER_RESOURCE_KEYS: RegisterResourceKey[] = ['actuators', 'sensors', 'bodies', 'joints', 'sites', 'geoms', 'keyframes'];
|
|
77
|
+
|
|
78
|
+
function createEmptyRuntimeResources(): Record<RegisterResourceKey, Record<string, string>> {
|
|
79
|
+
return {
|
|
80
|
+
actuators: {},
|
|
81
|
+
sensors: {},
|
|
82
|
+
bodies: {},
|
|
83
|
+
joints: {},
|
|
84
|
+
sites: {},
|
|
85
|
+
geoms: {},
|
|
86
|
+
keyframes: {},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function registerRobotResources(resources: RuntimeRobotResourceRegistration): void {
|
|
91
|
+
for (const [robot, robotResources] of Object.entries(resources)) {
|
|
92
|
+
const existing = runtimeRobotResources[robot] ?? createEmptyRuntimeResources();
|
|
93
|
+
for (const key of REGISTER_RESOURCE_KEYS) {
|
|
94
|
+
existing[key] = { ...existing[key], ...(robotResources[key] ?? {}) };
|
|
95
|
+
}
|
|
96
|
+
runtimeRobotResources[robot] = existing;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function createResourceCategory<TKey extends RegisterResourceKey>(key: TKey): RobotResourceCategory<TKey> {
|
|
101
|
+
return new Proxy({}, {
|
|
102
|
+
get(_target, robot) {
|
|
103
|
+
if (typeof robot !== 'string') return undefined;
|
|
104
|
+
return runtimeRobotResources[robot]?.[key] ?? {};
|
|
105
|
+
},
|
|
106
|
+
ownKeys() {
|
|
107
|
+
return Reflect.ownKeys(runtimeRobotResources);
|
|
108
|
+
},
|
|
109
|
+
getOwnPropertyDescriptor(_target, robot) {
|
|
110
|
+
if (typeof robot !== 'string' || !(robot in runtimeRobotResources)) return undefined;
|
|
111
|
+
return { enumerable: true, configurable: true };
|
|
112
|
+
},
|
|
113
|
+
}) as RobotResourceCategory<TKey>;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export const RobotResources: RobotResourceRegistry = new Proxy(runtimeRobotResources, {
|
|
117
|
+
get(target, robot) {
|
|
118
|
+
if (typeof robot !== 'string') return undefined;
|
|
119
|
+
return target[robot] ?? createEmptyRuntimeResources();
|
|
120
|
+
},
|
|
121
|
+
ownKeys(target) {
|
|
122
|
+
return Reflect.ownKeys(target);
|
|
123
|
+
},
|
|
124
|
+
getOwnPropertyDescriptor(target, robot) {
|
|
125
|
+
if (typeof robot !== 'string' || !(robot in target)) return undefined;
|
|
126
|
+
return { enumerable: true, configurable: true };
|
|
127
|
+
},
|
|
128
|
+
}) as RobotResourceRegistry;
|
|
129
|
+
|
|
130
|
+
export const RobotActuators: RobotResourceCategory<'actuators'> = createResourceCategory('actuators');
|
|
131
|
+
export const RobotSensors: RobotResourceCategory<'sensors'> = createResourceCategory('sensors');
|
|
132
|
+
export const RobotBodies: RobotResourceCategory<'bodies'> = createResourceCategory('bodies');
|
|
133
|
+
export const RobotJoints: RobotResourceCategory<'joints'> = createResourceCategory('joints');
|
|
134
|
+
export const RobotSites: RobotResourceCategory<'sites'> = createResourceCategory('sites');
|
|
135
|
+
export const RobotGeoms: RobotResourceCategory<'geoms'> = createResourceCategory('geoms');
|
|
136
|
+
export const RobotKeyframes: RobotResourceCategory<'keyframes'> = createResourceCategory('keyframes');
|
|
137
|
+
|
|
58
138
|
export type Actuators = Register extends { actuators: infer T extends string } ? T : string;
|
|
59
139
|
export type Sensors = Register extends { sensors: infer T extends string } ? T : string;
|
|
60
140
|
export type Bodies = Register extends { bodies: infer T extends string } ? T : string;
|
package/src/vite.ts
CHANGED
|
@@ -17,7 +17,7 @@ type ViteServer = {
|
|
|
17
17
|
export interface MujocoReactPluginOptions {
|
|
18
18
|
/** Entry MJCF/URDF files to scan. Prefer a record for stable per-robot type names. */
|
|
19
19
|
models: ModelInput;
|
|
20
|
-
/** Generated
|
|
20
|
+
/** Generated resource module. Defaults to `src/mujoco-register.gen.ts`. */
|
|
21
21
|
generatedRegister?: string;
|
|
22
22
|
/** Module name to augment. Defaults to `mujoco-react`. */
|
|
23
23
|
moduleName?: string;
|
|
@@ -65,7 +65,7 @@ function createEmptyNames(): Record<RegisterKey, Set<string>> {
|
|
|
65
65
|
export function mujocoReact(options: MujocoReactPluginOptions) {
|
|
66
66
|
const models = normalizeModels(options.models);
|
|
67
67
|
let root = process.cwd();
|
|
68
|
-
let generatedRegister = options.generatedRegister ?? 'src/mujoco-register.gen.
|
|
68
|
+
let generatedRegister = options.generatedRegister ?? 'src/mujoco-register.gen.ts';
|
|
69
69
|
let watchedFiles: string[] = [];
|
|
70
70
|
|
|
71
71
|
async function generate() {
|
|
@@ -90,6 +90,10 @@ export function mujocoReact(options: MujocoReactPluginOptions) {
|
|
|
90
90
|
root = config.root;
|
|
91
91
|
generatedRegister = path.resolve(root, generatedRegister);
|
|
92
92
|
},
|
|
93
|
+
transform(code: string, id: string) {
|
|
94
|
+
if (!shouldInjectRegisterImport(id, root, generatedRegister)) return;
|
|
95
|
+
return `${renderGeneratedImport(id, generatedRegister)}\n${code}`;
|
|
96
|
+
},
|
|
93
97
|
async buildStart(this: { addWatchFile?: (file: string) => void }) {
|
|
94
98
|
const result = await generate();
|
|
95
99
|
for (const file of result.files) this.addWatchFile?.(file);
|
|
@@ -122,6 +126,7 @@ export async function generateMujocoRegister(
|
|
|
122
126
|
const models = normalizeModels(options.models);
|
|
123
127
|
const names = createEmptyNames();
|
|
124
128
|
const seen = new Set<string>();
|
|
129
|
+
const declarationsOnly = out.endsWith('.d.ts');
|
|
125
130
|
|
|
126
131
|
for (const model of models) {
|
|
127
132
|
await scanModel(path.resolve(root, model.file), root, seen, model.names);
|
|
@@ -129,7 +134,7 @@ export async function generateMujocoRegister(
|
|
|
129
134
|
}
|
|
130
135
|
|
|
131
136
|
await mkdir(path.dirname(out), { recursive: true });
|
|
132
|
-
await writeFile(out, renderRegister(moduleName, names, models), 'utf8');
|
|
137
|
+
await writeFile(out, renderRegister(moduleName, names, models, declarationsOnly), 'utf8');
|
|
133
138
|
|
|
134
139
|
return {
|
|
135
140
|
out,
|
|
@@ -200,30 +205,74 @@ function readAttr(attrs: string, attr: string): string | undefined {
|
|
|
200
205
|
function renderRegister(
|
|
201
206
|
moduleName: string,
|
|
202
207
|
names: Record<RegisterKey, Set<string>>,
|
|
203
|
-
models: readonly ModelEntry[]
|
|
208
|
+
models: readonly ModelEntry[],
|
|
209
|
+
declarationsOnly: boolean
|
|
204
210
|
): string {
|
|
205
211
|
const fields = REGISTER_KEYS
|
|
206
212
|
.filter((key) => names[key].size > 0)
|
|
207
213
|
.map((key) => ` ${key}: ${renderUnion(names[key])};`);
|
|
208
214
|
const robots = models
|
|
209
215
|
.map((model) => ` ${quoteProperty(model.id)}: {\n${renderRobotFields(model.names)}\n };`);
|
|
216
|
+
const namespaceAliases = renderNamespaceAliases(models);
|
|
217
|
+
const registerImport = declarationsOnly ? '' : `import { registerRobotResources } from '${moduleName}';\n`;
|
|
218
|
+
const resources = declarationsOnly ? '' : `${renderResourceTypes(models)}\n\n${renderResourceConstants(models)}\n\nregisterRobotResources(generatedRobotResources);\n\n`;
|
|
210
219
|
|
|
211
220
|
return `// Auto-generated by mujoco-react. Do not edit.
|
|
212
221
|
// Regenerate by running Vite with the mujocoReact() plugin or \`mujoco-react codegen\`.
|
|
213
222
|
|
|
214
|
-
import '
|
|
223
|
+
${registerImport}import type { RobotResource } from '${moduleName}';
|
|
215
224
|
|
|
216
|
-
declare module '${moduleName}' {
|
|
225
|
+
${resources}declare module '${moduleName}' {
|
|
217
226
|
interface Register {
|
|
218
227
|
robots: {
|
|
219
228
|
${robots.join('\n')}
|
|
220
229
|
};
|
|
221
230
|
${fields.join('\n')}
|
|
222
231
|
}
|
|
232
|
+
|
|
233
|
+
${namespaceAliases}
|
|
223
234
|
}
|
|
224
235
|
`;
|
|
225
236
|
}
|
|
226
237
|
|
|
238
|
+
function renderResourceTypes(models: readonly ModelEntry[]): string {
|
|
239
|
+
const modelTypes = models
|
|
240
|
+
.map((model) => ` readonly ${quoteProperty(model.id)}: {\n${renderResourceTypeFields(model.names)}\n };`)
|
|
241
|
+
.join('\n');
|
|
242
|
+
return `type GeneratedRobotResources = {\n${modelTypes}\n};`;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function renderResourceTypeFields(names: Record<RegisterKey, Set<string>>): string {
|
|
246
|
+
return REGISTER_KEYS
|
|
247
|
+
.map((key) => ` readonly ${key}: ${renderResourceObjectType(names[key])};`)
|
|
248
|
+
.join('\n');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function renderResourceObjectType(values: Set<string>): string {
|
|
252
|
+
const entries = sortedValues(values)
|
|
253
|
+
.map((value) => ` readonly ${quoteProperty(value)}: '${escapeTs(value)}';`);
|
|
254
|
+
return entries.length > 0 ? `{\n${entries.join('\n')}\n }` : '{}';
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function renderResourceConstants(models: readonly ModelEntry[]): string {
|
|
258
|
+
const entries = models
|
|
259
|
+
.map((model) => ` ${quoteProperty(model.id)}: {\n${renderResourceConstantFields(model.names)}\n },`)
|
|
260
|
+
.join('\n');
|
|
261
|
+
return `const generatedRobotResources: GeneratedRobotResources = {\n${entries}\n};`;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function renderResourceConstantFields(names: Record<RegisterKey, Set<string>>): string {
|
|
265
|
+
return REGISTER_KEYS
|
|
266
|
+
.map((key) => ` ${key}: ${renderResourceObject(names[key])},`)
|
|
267
|
+
.join('\n');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function renderResourceObject(values: Set<string>): string {
|
|
271
|
+
const entries = sortedValues(values)
|
|
272
|
+
.map((value) => ` ${quoteProperty(value)}: '${escapeTs(value)}',`);
|
|
273
|
+
return entries.length > 0 ? `{\n${entries.join('\n')}\n }` : '{}';
|
|
274
|
+
}
|
|
275
|
+
|
|
227
276
|
function renderRobotFields(names: Record<RegisterKey, Set<string>>): string {
|
|
228
277
|
return REGISTER_KEYS
|
|
229
278
|
.map((key) => ` ${key}: ${names[key].size > 0 ? renderUnion(names[key]) : 'never'};`)
|
|
@@ -231,15 +280,73 @@ function renderRobotFields(names: Record<RegisterKey, Set<string>>): string {
|
|
|
231
280
|
}
|
|
232
281
|
|
|
233
282
|
function renderUnion(values: Set<string>): string {
|
|
234
|
-
return
|
|
283
|
+
return sortedValues(values).map((value) => `'${escapeTs(value)}'`).join(' | ');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function renderNamespaceAliases(models: readonly ModelEntry[]): string {
|
|
287
|
+
const namespaces: Record<RegisterKey, string> = {
|
|
288
|
+
actuators: 'RobotActuators',
|
|
289
|
+
sensors: 'RobotSensors',
|
|
290
|
+
bodies: 'RobotBodies',
|
|
291
|
+
joints: 'RobotJoints',
|
|
292
|
+
sites: 'RobotSites',
|
|
293
|
+
geoms: 'RobotGeoms',
|
|
294
|
+
keyframes: 'RobotKeyframes',
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const blocks = REGISTER_KEYS
|
|
298
|
+
.map((key) => {
|
|
299
|
+
const aliases = models
|
|
300
|
+
.filter((model) => isIdentifier(model.id))
|
|
301
|
+
.map((model) => ` export type ${model.id} = RobotResource<'${escapeTs(model.id)}', '${key}'>;`);
|
|
302
|
+
if (aliases.length === 0) return '';
|
|
303
|
+
return ` export namespace ${namespaces[key]} {\n${aliases.join('\n')}\n }`;
|
|
304
|
+
})
|
|
305
|
+
.filter(Boolean)
|
|
306
|
+
.join('\n\n');
|
|
307
|
+
|
|
308
|
+
return blocks ? `${blocks}\n` : '';
|
|
235
309
|
}
|
|
236
310
|
|
|
237
311
|
function escapeTs(value: string): string {
|
|
238
312
|
return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
239
313
|
}
|
|
240
314
|
|
|
315
|
+
function sortedValues(values: Set<string>): string[] {
|
|
316
|
+
return [...values].sort((a, b) => a.localeCompare(b));
|
|
317
|
+
}
|
|
318
|
+
|
|
241
319
|
function quoteProperty(value: string): string {
|
|
242
|
-
return
|
|
320
|
+
return isIdentifier(value) ? value : `'${escapeTs(value)}'`;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function isIdentifier(value: string): boolean {
|
|
324
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function toPosixPath(value: string): string {
|
|
328
|
+
return value.split(path.sep).join('/');
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function shouldInjectRegisterImport(id: string, root: string, generatedRegister: string): boolean {
|
|
332
|
+
if (generatedRegister.endsWith('.d.ts')) return false;
|
|
333
|
+
const file = stripQuery(id);
|
|
334
|
+
if (!/\.[cm]?[jt]sx?$/.test(file)) return false;
|
|
335
|
+
if (file.includes(`${path.sep}node_modules${path.sep}`)) return false;
|
|
336
|
+
const absolute = path.resolve(file);
|
|
337
|
+
if (absolute === generatedRegister) return false;
|
|
338
|
+
return absolute.startsWith(root);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function renderGeneratedImport(id: string, generatedRegister: string): string {
|
|
342
|
+
const fromDir = path.dirname(stripQuery(id));
|
|
343
|
+
let relative = toPosixPath(path.relative(fromDir, generatedRegister));
|
|
344
|
+
if (!relative.startsWith('.')) relative = `./${relative}`;
|
|
345
|
+
return `import '${relative}';`;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function stripQuery(id: string): string {
|
|
349
|
+
return id.split('?')[0];
|
|
243
350
|
}
|
|
244
351
|
|
|
245
352
|
function normalizeModels(input: ModelInput): ModelEntry[] {
|