diff --git a/src/cli/find-config.ts b/src/cli/find-config.ts index df8b1414..03a4174b 100644 --- a/src/cli/find-config.ts +++ b/src/cli/find-config.ts @@ -8,7 +8,7 @@ import type { CompilerSystem, Diagnostic } from '../declarations'; */ export type FindConfigOptions = { sys: CompilerSystem; - configPath: string; + configPath?: string | null; }; /** @@ -38,7 +38,7 @@ export const findConfig = async (opts: FindConfigOptions): Promise d.level === 'error')) { @@ -27,9 +27,9 @@ export const taskPrerender = async (coreCompiler: CoreCompiler, config: Validate export const runPrerenderTask = async ( coreCompiler: CoreCompiler, config: ValidatedConfig, - hydrateAppFilePath: string, - componentGraph: BuildResultsComponentGraph, - srcIndexHtmlPath: string, + hydrateAppFilePath?: string, + componentGraph?: BuildResultsComponentGraph, + srcIndexHtmlPath?: string, ) => { const diagnostics: Diagnostic[] = []; diff --git a/src/cli/task-serve.ts b/src/cli/task-serve.ts index 515b0b7f..b789e9ea 100644 --- a/src/cli/task-serve.ts +++ b/src/cli/task-serve.ts @@ -13,6 +13,12 @@ export const taskServe = async (config: ValidatedConfig) => { config.maxConcurrentWorkers = 1; config.devServer.root = isString(config.flags.root) ? config.flags.root : config.sys.getCurrentDirectory(); + if (!config.sys.getDevServerExecutingPath || !config.sys.dynamicImport || !config.sys.onProcessInterrupt) { + throw new Error( + `Environment doesn't provide required functions: getDevServerExecutingPath, dynamicImport, onProcessInterrupt`, + ); + } + const devServerPath = config.sys.getDevServerExecutingPath(); const { start }: typeof import('@rindo/core/dev-server') = await config.sys.dynamicImport(devServerPath); const devServer = await start(config.devServer, config.logger); diff --git a/src/cli/task-test.ts b/src/cli/task-test.ts index 6f6b0d49..a5eddb83 100644 --- a/src/cli/task-test.ts +++ b/src/cli/task-test.ts @@ -35,8 +35,8 @@ export const taskTest = async (config: ValidatedConfig): Promise => { } // ensure we've got the required modules installed - const diagnostics = await config.sys.lazyRequire.ensure(config.rootDir, ensureModuleIds); - if (diagnostics.length > 0) { + const diagnostics = await config.sys.lazyRequire?.ensure(config.rootDir, ensureModuleIds); + if (diagnostics && diagnostics.length > 0) { config.logger.printDiagnostics(diagnostics); return config.sys.exit(1); } diff --git a/src/cli/task-watch.ts b/src/cli/task-watch.ts index 7cc68491..6278eb11 100644 --- a/src/cli/task-watch.ts +++ b/src/cli/task-watch.ts @@ -15,6 +15,12 @@ export const taskWatch = async (coreCompiler: CoreCompiler, config: ValidatedCon const compiler = await coreCompiler.createCompiler(config); const watcher = await compiler.createWatcher(); + if (!config.sys.getDevServerExecutingPath || !config.sys.dynamicImport || !config.sys.onProcessInterrupt) { + throw new Error( + `Environment doesn't provide required functions: getDevServerExecutingPath, dynamicImport, onProcessInterrupt`, + ); + } + if (config.flags.serve) { const devServerPath = config.sys.getDevServerExecutingPath(); const { start }: typeof import('@rindo/core/dev-server') = await config.sys.dynamicImport(devServerPath); diff --git a/src/cli/telemetry/telemetry.ts b/src/cli/telemetry/telemetry.ts index d08770ee..466c086f 100644 --- a/src/cli/telemetry/telemetry.ts +++ b/src/cli/telemetry/telemetry.ts @@ -99,7 +99,7 @@ export function hasAppTarget(config: d.ValidatedConfig): boolean { } export function isUsingYarn(sys: d.CompilerSystem) { - return sys.getEnvironmentVar('npm_execpath')?.includes('yarn') || false; + return sys.getEnvironmentVar?.('npm_execpath')?.includes('yarn') || false; } /** @@ -347,12 +347,12 @@ async function npmPackages(sys: d.CompilerSystem, familyPackages: [string, strin async function yarnPackages(sys: d.CompilerSystem, familyPackages: [string, string][]): Promise { const appRootDir = sys.getCurrentDirectory(); const yarnLock = sys.readFileSync(sys.resolvePath(appRootDir + '/yarn.lock')); - const yarnLockYml = sys.parseYarnLockFile(yarnLock); + const yarnLockYml = sys.parseYarnLockFile?.(yarnLock); return familyPackages.map(([k, v]) => { const identifiedVersion = `${k}@${v}`; - let version = yarnLockYml.object[identifiedVersion]?.version; - version = version.includes('undefined') ? sanitizeDeclaredVersion(identifiedVersion) : version; + let version = yarnLockYml?.object[identifiedVersion]?.version; + version = version && version.includes('undefined') ? sanitizeDeclaredVersion(identifiedVersion) : version; return `${k}@${version}`; }); } @@ -425,6 +425,10 @@ async function sendTelemetry(sys: d.CompilerSystem, config: d.ValidatedConfig, d sent_at: now, }; + if (!sys.fetch) { + throw new Error('No fetch implementation available'); + } + // This request is only made if telemetry is on. const response = await sys.fetch('https://familyjs-api.web.app/events/metrics', { method: 'POST', diff --git a/src/client/client-load-module.ts b/src/client/client-load-module.ts index 256c76e3..10c6f4e0 100644 --- a/src/client/client-load-module.ts +++ b/src/client/client-load-module.ts @@ -27,7 +27,7 @@ export const loadModule = ( cmpMeta: d.ComponentRuntimeMeta, hostRef: d.HostRef, hmrVersionId?: string, -): Promise | d.ComponentConstructor => { +): Promise | d.ComponentConstructor | undefined => { // loadModuleImport const exportName = cmpMeta.$tagName$.replace(/-/g, '_'); const bundleId = cmpMeta.$lazyBundleId$; @@ -36,6 +36,8 @@ export const loadModule = ( `Trying to lazily load component <${cmpMeta.$tagName$}> with style mode "${hostRef.$modeName$}", but it does not exist.`, ); return undefined; + } else if (!bundleId) { + return undefined; } const module = !BUILD.hotModuleReplacement ? cmpModules.get(bundleId) : false; if (module) { diff --git a/src/declarations/rindo-public-compiler.ts b/src/declarations/rindo-public-compiler.ts index 48fb025e..63b56cc0 100644 --- a/src/declarations/rindo-public-compiler.ts +++ b/src/declarations/rindo-public-compiler.ts @@ -2643,9 +2643,9 @@ export interface ResolveModuleOptions { export interface PrerenderStartOptions { buildId?: string; - hydrateAppFilePath: string; - componentGraph: BuildResultsComponentGraph; - srcIndexHtmlPath: string; + hydrateAppFilePath?: string; + componentGraph?: BuildResultsComponentGraph; + srcIndexHtmlPath?: string; } export interface PrerenderResults { diff --git a/src/runtime/host-listener.ts b/src/runtime/host-listener.ts index e7b27f1c..f323b700 100644 --- a/src/runtime/host-listener.ts +++ b/src/runtime/host-listener.ts @@ -7,8 +7,8 @@ import type * as d from '../declarations'; export const addHostEventListeners = ( elm: d.HostElement, hostRef: d.HostRef, - listeners: d.ComponentRuntimeHostListener[], - attachParentListeners: boolean, + listeners?: d.ComponentRuntimeHostListener[], + attachParentListeners?: boolean, ) => { if (BUILD.hostListener && listeners) { // this is called immediately within the element's constructor @@ -46,7 +46,7 @@ const hostListenerProxy = (hostRef: d.HostRef, methodName: string) => (ev: Event if (BUILD.lazyLoad) { if (hostRef.$flags$ & HOST_FLAGS.isListenReady) { // instance is ready, let's call it's member method for this event - hostRef.$lazyInstance$[methodName](ev); + hostRef.$lazyInstance$?.[methodName](ev); } else { (hostRef.$queuedListeners$ = hostRef.$queuedListeners$ || []).push([methodName, ev]); } @@ -62,7 +62,8 @@ const getHostListenerTarget = (elm: Element, flags: number): EventTarget => { if (BUILD.hostListenerTargetDocument && flags & LISTENER_FLAGS.TargetDocument) return doc; if (BUILD.hostListenerTargetWindow && flags & LISTENER_FLAGS.TargetWindow) return win; if (BUILD.hostListenerTargetBody && flags & LISTENER_FLAGS.TargetBody) return doc.body; - if (BUILD.hostListenerTargetParent && flags & LISTENER_FLAGS.TargetParent) return elm.parentElement; + if (BUILD.hostListenerTargetParent && flags & LISTENER_FLAGS.TargetParent && elm.parentElement) + return elm.parentElement; return elm; }; diff --git a/src/screenshot/pixel-match.ts b/src/screenshot/pixel-match.ts index ca469c72..c92a7e09 100644 --- a/src/screenshot/pixel-match.ts +++ b/src/screenshot/pixel-match.ts @@ -17,6 +17,10 @@ function getMismatchedPixels(pixelMatchInput: d.PixelMatchInput) { includeAA: false, }); + if (typeof process.send !== 'function') { + throw new Error('`getMismatchedPixels` must be run in a child process.'); + } + process.send(mismatchedPixels); } } diff --git a/src/screenshot/screenshot-compare.ts b/src/screenshot/screenshot-compare.ts index 7b9be8d9..2c468d95 100644 --- a/src/screenshot/screenshot-compare.ts +++ b/src/screenshot/screenshot-compare.ts @@ -27,7 +27,6 @@ export async function compareScreenshot( const currentImagePath = join(screenshotBuildData.imagesDir, currentImageName); await writeScreenshotImage(currentImagePath, currentScreenshotBuf); - currentScreenshotBuf = null; if (testPath) { testPath = normalizePath(relative(screenshotBuildData.rootDir, testPath)); @@ -179,7 +178,7 @@ async function getMismatchedPixels( reject(err); }); - pixelMatchProcess.stderr.on('data', (data) => { + pixelMatchProcess.stderr?.on('data', (data) => { error = data.toString(); }); diff --git a/src/screenshot/screenshot-fs.ts b/src/screenshot/screenshot-fs.ts index 628bd06c..3d96e850 100644 --- a/src/screenshot/screenshot-fs.ts +++ b/src/screenshot/screenshot-fs.ts @@ -16,7 +16,7 @@ export async function writeScreenshotData(dataDir: string, screenshotData: d.Scr } export async function readScreenshotData(dataDir: string, screenshotId: string) { - let rtn: d.Screenshot = null; + let rtn: d.Screenshot | null = null; try { const dataFilePath = getDataFilePath(dataDir, screenshotId); diff --git a/src/sys/node/logger/index.ts b/src/sys/node/logger/index.ts index a03dcbd8..0f824fbb 100644 --- a/src/sys/node/logger/index.ts +++ b/src/sys/node/logger/index.ts @@ -70,7 +70,7 @@ export function createNodeLoggerSys(): TerminalLoggerSys { return (promise = promise.then(() => { return new Promise((resolve) => { readline.clearLine(process.stdout, 0); - readline.cursorTo(process.stdout, 0, null); + readline.cursorTo(process.stdout, 0, undefined); process.stdout.write(text, resolve); }); })); diff --git a/src/sys/node/logger/terminal-logger.ts b/src/sys/node/logger/terminal-logger.ts index 67ce1fa8..1fbdce34 100644 --- a/src/sys/node/logger/terminal-logger.ts +++ b/src/sys/node/logger/terminal-logger.ts @@ -110,7 +110,7 @@ export const createTerminalLogger = (loggerSys: TerminalLoggerSys): Logger => { } }; - const timespanStart = (startMsg: string, debug: boolean, appendTo: string[]) => { + const timespanStart = (startMsg: string, debug: boolean, appendTo?: string[]) => { const msg = [`${startMsg} ${dim('...')}`]; if (debug) { @@ -151,7 +151,7 @@ export const createTerminalLogger = (loggerSys: TerminalLoggerSys): Logger => { textBold: boolean, newLineSuffix: boolean, debug: boolean, - appendTo: string[], + appendTo?: string[], ) => { let msg = finishMsg; @@ -400,7 +400,7 @@ export const createTerminalLogger = (loggerSys: TerminalLoggerSys): Logger => { * @param errorLength the length of the error, how many characters should be highlighted * @returns the highlighted error */ - const highlightError = (errorLine: string, errorCharStart: number, errorLength: number): string => { + const highlightError = (errorLine: string, errorCharStart: number, errorLength: number = 0): string => { let rightSideChars = errorLine.length - errorCharStart + errorLength - 1; while (errorLine.length + INDENT.length > loggerSys.getColumns()) { if (errorCharStart > errorLine.length - errorCharStart + errorLength && errorCharStart > 5) { diff --git a/src/testing/jest/jest-rindo-connector.ts b/src/testing/jest/jest-rindo-connector.ts index 19905372..c65972d4 100644 --- a/src/testing/jest/jest-rindo-connector.ts +++ b/src/testing/jest/jest-rindo-connector.ts @@ -43,15 +43,19 @@ const getJestFacade = (): JestFacade => { if (version <= 27) { JEST_RINDO_FACADE = new Jest27Rindo(); } else if (version === 28) { - JEST_RINDO_FACADE = new Jest28Rindo(); + JEST_RINDO_FACADE = new Jest28Rindo() as JestFacade; } else if (version === 29) { - JEST_RINDO_FACADE = new Jest29Rindo(); + JEST_RINDO_FACADE = new Jest29Rindo() as JestFacade; } else { // in Rindo 4.X, defaulting to jest 27 infrastructure is the default behavior. JEST_RINDO_FACADE = new Jest27Rindo(); } } + if (!JEST_RINDO_FACADE) { + throw new Error('Rindo could not determine the Jest version being used.'); + } + return JEST_RINDO_FACADE; }; diff --git a/src/testing/mock-fetch.ts b/src/testing/mock-fetch.ts index 8e1c356d..7cb597c7 100644 --- a/src/testing/mock-fetch.ts +++ b/src/testing/mock-fetch.ts @@ -103,7 +103,7 @@ export function mockFetchReset() { } export const mockFetch = { - json(data: any, url?: string) { + json(data: any, url: string) { const rsp = new MockResponse(JSON.stringify(data, null, 2), { headers: new MockHeaders({ 'Content-Type': 'application/json', @@ -112,7 +112,7 @@ export const mockFetch = { setMockedResponse(rsp, url, false); }, - text(data: string, url?: string) { + text(data: string, url: string) { const rsp = new MockResponse(data, { headers: new MockHeaders({ 'Content-Type': 'text/plain', @@ -121,11 +121,11 @@ export const mockFetch = { setMockedResponse(rsp, url, false); }, - response(rsp: MockResponse, url?: string) { + response(rsp: MockResponse, url: string) { setMockedResponse(rsp, url, false); }, - reject(rsp?: MockResponse, url?: string) { + reject(rsp: MockResponse, url: string) { setMockedResponse(rsp, url, true); },