-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Overview
Optional: Consider internalizing RWGPSLib into the codebase following Core/Adapter pattern.
Decision Criteria
Should only proceed if:
- ✅ You need features RWGPSLib doesn't provide
- ✅ You're comfortable maintaining OAuth/API code
- ✅ RWGPSLib has caused production issues
- ✅ You want extensive testing around RWGPS operations
Skip if:
- ❌ External library works fine (less maintenance burden)
- ❌ No specific pain points with current implementation
Proposed Architecture
// RWGPSCore.js - Pure JavaScript
class RWGPSCore {
static prepareEventPayload(event) {
// Pure JSON building logic
// 100% testable
}
static parseEventResponse(json) {
// Pure response parsing
// 100% testable
}
static validateEventData(event) {
// Pure validation
// 100% testable
}
}
// RWGPSAdapter.js - GAS API calls
class RWGPSAdapter {
constructor(apiKey) {
this.apiKey = apiKey;
}
getEvent(url) {
const response = UrlFetchApp.fetch(url + '.json');
return RWGPSCore.parseEventResponse(
JSON.parse(response.getContentText())
);
}
}Success Criteria (If Proceeding)
- RWGPSLib code copied into src/
- Comprehensive type definitions in Externals.d.ts
- RWGPSCore.js with pure business logic
- RWGPSCore.test.js with 100% coverage
- RWGPSAdapter.js as thin GAS wrapper
- RideManager updated to use RWGPSAdapter
- All RWGPS operations tested
- Zero regression in production
Effort Estimate
4-7 days
Dependencies
CRITICAL: Must complete Phase 1 (Issues #171, #172, #173) BEFORE considering this
Recommendation
Defer this decision until Phase 1 complete. External library is likely fine.
References
- Architecture Plan: docs/Architecture-Refactoring-Plan.md
- Copilot Instructions: .github/copilot-instructions.md
Note on This Issue
This is an optional/deferred issue. Recommendation is to skip unless there's a clear need.
The external RWGPSLib library is working well, and internalizing it adds maintenance burden. Only proceed if:
- RWGPSLib is causing production issues
- You need features it doesn't provide
- You want extensive testing around RWGPS operations
Copilot Execution Checklist
Before Starting
- Read
.github/copilot-instructions.mdsections: Architecture Overview, Module Addition Checklist, TypeScript Type Coverage - Understand Core vs Adapter separation pattern (Core = pure JS with 100% tests, Adapter = thin GAS wrapper)
- CRITICAL: Understand GAS conditional module pattern (works in BOTH Jest and GAS)
GAS-Compatible Module Pattern
MANDATORY: All modules must work in BOTH Jest (with require/module.exports) AND GAS (no modules, global scope):
// At top of file - Jest compatibility
if (typeof require !== 'undefined') {
var SomeDependency = require('./SomeDependency'); // Use 'var', not 'const'!
}
// Module definition using IIFE
var ModuleName = (function() {
class ModuleName {
// Implementation
}
return ModuleName;
})();
// At bottom - Jest export
if (typeof module !== 'undefined') {
module.exports = ModuleName; // Export the class/object
}Why this works:
if (typeof require !== 'undefined')- Only runs in Jest (Node.js environment)vardeclarations - Hoisted in GAS, can be redeclared without error- IIFE pattern - Works in both environments
if (typeof module !== 'undefined')- Only runs in Jest for exports- In GAS: All files concatenated to global scope,
ModuleNamebecomes global variable
Implementation Steps
-
Create Core module -
src/ModuleNameCore.js- Write pure JavaScript business logic (NO GAS APIs)
- Use dependency injection pattern (pass dependencies as parameters)
- Follow conditional module pattern above
- Variable name MUST match class/module name
-
Create tests FIRST -
test/__tests__/ModuleNameCore.test.js- Achieve 100% coverage BEFORE writing adapter
- Run:
npm test -- --coverage --collectCoverageFrom='src/ModuleNameCore.js' - Must show 100% statements/branches/functions/lines
- Only acceptable uncovered:
if (typeof require !== 'undefined')compatibility checks
-
Create type definitions -
src/ModuleNameCore.d.ts- Add JSDoc comments to all functions in
.jsfile - Use
declare namespacefor namespace objects (e.g.,var X = { method1: ..., method2: ... }) - Use
declare classfor class constructors (e.g.,class X { ... }) - Export default:
export default ModuleNameCore;
- Add JSDoc comments to all functions in
-
Update Exports.js - Add module to
src/Exports.jsget ModuleNameCore() { return ModuleNameCore; // Property name MUST match variable name }
- Run:
npm run validate-exports(must pass - verifies module is defined)
- Run:
-
MANDATORY: Check VS Code errors
- Run:
get_errors(['src/ModuleNameCore.js', 'src/ModuleNameCore.d.ts']) - Fix ALL errors before proceeding (zero tolerance)
- CRITICAL: VS Code TypeScript server is MORE STRICT than
tsc --noEmit - Common fixes:
- Add
/** @type {any[]} */for array variables - Add
/** @param {T} paramName */to all function parameters - Add error type guards:
const err = error instanceof Error ? error : new Error(String(error));
- Add
- Run:
-
Refactor adapter (if updating existing file) -
src/ModuleName.js- Keep ONLY GAS API calls (SpreadsheetApp, PropertiesService, etc.)
- Delegate all logic to Core module
- Update corresponding
.d.tsfile - Run
get_errorsagain
-
Final validation
npm run typecheck && npm run validate-exports && npm test
- ALL must pass with ZERO errors
-
Deploy and test
npm run dev:push
- Manual testing in GAS environment
- Check spreadsheet menu: "Ride Schedulers" > "Show Version" to verify deployment
- Check User Activity Log for any errors
- Test the specific functionality you modified
Completion Criteria
- All checkboxes in "Success Criteria" section checked
- Zero VS Code errors:
get_errors(['src/'])shows none - 100% test coverage for Core module
-
npm run typecheckpasses (ZERO errors) -
npm run validate-exportspasses -
npm testpasses (all tests green) - Manual testing successful in dev environment
- No regressions in production functionality