@@ -26,6 +26,7 @@ import {
2626} from "react" ;
2727import { MAIN_FILE , VersionAction } from "../fs/fs" ;
2828import { useFileSystem } from "../fs/fs-hooks" ;
29+ import { extractModuleData } from "../fs/fs-util" ;
2930import { parseRoles , ParsedRole } from "./parse-roles" ;
3031import { JACDAC_MODULES } from "./python/module-source" ;
3132import { SupportedService , supportedServiceByClass } from "./supported-services" ;
@@ -127,11 +128,16 @@ export const useJacdacIdentify = (): ((deviceId: string) => Promise<void>) => {
127128} ;
128129
129130/**
130- * Ensure each Jacdac sensor module (JacdacButton.py, etc.) is a project file
131- * whenever the user's code uses that class, so the import resolves at runtime
132- * (in the simulator) and the user can read the module. Only the modules
133- * actually used are added, keeping the flat filesystem lean. Added as micro:bit
134- * module files.
131+ * Keep the Jacdac sensor modules (JacdacButton.py, etc.) in sync with the user's
132+ * code: add a module file whenever the code uses that class (so the import
133+ * resolves in the simulator and the user can read it), and remove it again once
134+ * the code no longer references the class. Only used modules are present, keeping
135+ * the flat filesystem lean. Added/removed as micro:bit module files.
136+ *
137+ * Removal is guarded by the magic module comment: we only delete a file we
138+ * recognise as our own module (matching class name), so a user's own same-named
139+ * file is left untouched. This does mean edits to an added module file are lost
140+ * if the last reference is removed.
135141 */
136142export const useEnsureJacdacModules = ( ) : void => {
137143 const fs = useFileSystem ( ) ;
@@ -149,8 +155,16 @@ export const useEnsureJacdacModules = (): void => {
149155 }
150156 const used = new RegExp ( `\\b${ module . className } \\b` ) . test ( text ) ;
151157 const filename = `${ module . className } .py` ;
152- if ( used && ! ( await fs . exists ( filename ) ) ) {
158+ const exists = await fs . exists ( filename ) ;
159+ if ( used && ! exists ) {
153160 await fs . write ( filename , module . source , VersionAction . INCREMENT ) ;
161+ } else if ( ! used && exists ) {
162+ const existing = new TextDecoder ( ) . decode (
163+ ( await fs . read ( filename ) ) . data
164+ ) ;
165+ if ( extractModuleData ( existing ) ?. name === module . className ) {
166+ await fs . remove ( filename ) ;
167+ }
154168 }
155169 }
156170 } catch {
0 commit comments