Browse / github.com/storytold/artcraft-services / patch
fix: stop testing promises in conditionals (SonarCloud S6544)
fix: stop testing promises in conditionals (SonarCloud S6544) Resolves the 20 `typescript:S6544` findings. - **Cached promises** (`create-3d-modal`, `DndAsset`, `ammoLoader`, `google-fonts`, `audio-manager`, `waveform-cache`, `video-cache`, `image-node`, `sticker-node`, `hero-wordmark`, `heading-flow`): `if (promise)` is always true, so each now narrows by identity (`=== undefined` / `!== null`). Same behaviour, no always-true branch. - **`SceneManagerAPI`**: the interface declared `void` while `SceneManager` returned promises for `create`/`retrieve`/`update`/`delete`; the interface now matches the implementation. - **`scene.ts`**: both CORS-less loader
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- dylanmtaylor (imported from pull request #181, open)
- Base
e57ee3d63ac478a24149384bf1473ef97aa067f8- Size
- +75 −69 in 14 files
- Review
- pending
- Shared
- 2026-10-28
- Id
8384d6a06ea959a643fcef0e
How it went
No other operator has reported using it yet.
Diff
raw · frontend/apps/artcraft-website-next/src/components/landing/hero-wordmark.tsx frontend/apps/artcraft-website-next/src/components/ruler/heading-flow.tsx frontend/libs/components/create-3d-modal/src/lib/create-3d-modal.tsx frontend/libs/components/pagescene/src/lib/DragAndDrop/DndAsset.ts frontend/libs/components/pagescene/src/lib/engine/ammoLoader.ts frontend/libs/components/pagescene/src/lib/engine/scene.ts frontend/libs/components/pagescene/src/lib/engine/scene_manager_api.ts frontend/libs/components/upload-modal/src/lib/UploadModal3D/utilities/convertFbxToGlb.worker.ts frontend/libs/components/video-editor/src/lib/core/managers/audio-manager.ts frontend/libs/components/video-editor/src/lib/fonts/google-fonts.ts frontend/libs/components/video-editor/src/lib/services/renderer/nodes/image-node.ts frontend/libs/components/video-editor/src/lib/services/renderer/nodes/sticker-node.ts frontend/libs/components/video-editor/src/lib/services/video-cache/service.ts frontend/libs/components/video-editor/src/lib/services/waveform-cache/service.ts
@@ -166,7 +166,7 @@ export default function HeroMasthead() { }; const ready = document.fonts?.ready;- if (ready) ready.then(compute).catch(compute);+ if (ready !== undefined) ready.then(compute).catch(compute); else compute(); const ro = new ResizeObserver(compute); ro.observe(box);@@ -167,7 +167,7 @@ export default function HeadingFlow({ setMetrics(measureLabels(sections.map((s) => s.label))); }; const ready = document.fonts?.ready;- if (ready) ready.then(run).catch(run);+ if (ready !== undefined) ready.then(run).catch(run); else run(); return () => { cancelled = true;@@ -38,7 +38,7 @@ export const Create3dModal = ({ onModelComplete }: Create3dModalProps = {}) => { // Listen for generation complete events useEffect(() => { let isUnmounted = false;- let unlisten: Promise<UnlistenFn>;+ let unlisten: Promise<UnlistenFn> | undefined; const setup = async () => { unlisten = listen("generation-complete-event", (event: any) => {@@ -102,7 +102,7 @@ export const Create3dModal = ({ onModelComplete }: Create3dModalProps = {}) => { return () => { isUnmounted = true;- if (unlisten) {+ if (unlisten !== undefined) { unlisten.then((f) => f()); } };@@ -273,7 +273,7 @@ class DndAsset { return; } const inspection = this.clipNodeNamesCache.get(item.media_id);- if (!inspection) {+ if (inspection === undefined) { // No inspection in flight (shouldn't happen — pointer-down starts // one): add unvalidated, matching the ungated click-to-add path. this.completeAnimationDrop(editor, item, target, undefined);@@ -8,7 +8,7 @@ let ammoLoadPromise: Promise<void> | null = null; export const ensureAmmoLoaded = (): Promise<void> => {- if (ammoLoadPromise) return ammoLoadPromise;+ if (ammoLoadPromise !== null) return ammoLoadPromise; ammoLoadPromise = new Promise<void>((resolve, reject) => { if (typeof document === "undefined") {@@ -1026,22 +1026,21 @@ class Scene { onComplete: () => void, signal?: AbortSignal, ): Promise<GLTF> {- return new Promise<GLTF>(async (resolve, reject) => {- let buffer;- try {- // Host-supplied CORS-bypassed binary fetch (FetchProxy under- // Tauri; plain fetch under web hosts that allow it).- buffer = await (- await this.deps.fetchAsset(media_url, { signal })- ).arrayBuffer();- } catch (error) {- if ((error as { name?: string })?.name !== "AbortError") {- console.error("load GLB from Tauri error:", error);- }- reject(error);- return;+ let buffer;+ try {+ // Host-supplied CORS-bypassed binary fetch (FetchProxy under+ // Tauri; plain fetch under web hosts that allow it).+ buffer = await (+ await this.deps.fetchAsset(media_url, { signal })+ ).arrayBuffer();+ } catch (error) {+ if ((error as { name?: string })?.name !== "AbortError") {+ console.error("load GLB from Tauri error:", error); }- const glbLoader = new GLTFLoader();+ throw error;+ }+ const glbLoader = new GLTFLoader();+ return new Promise<GLTF>((resolve, reject) => { glbLoader.parse( buffer, "", // NB: No relative path to load additional assets!@@ -1068,22 +1067,21 @@ class Scene { onComplete: () => void, signal?: AbortSignal, ): Promise<SplatMesh> {- return new Promise(async (resolve, reject) => {- let buffer;- try {- // Host-supplied CORS-bypassed binary fetch (FetchProxy under- // Tauri; plain fetch under web hosts that allow it).- buffer = await (- await this.deps.fetchAsset(media_url, { signal })- ).arrayBuffer();- } catch (error) {- if ((error as { name?: string })?.name !== "AbortError") {- console.error("load Splat from Tauri error:", error);- }- reject(error);- return;+ let buffer;+ try {+ // Host-supplied CORS-bypassed binary fetch (FetchProxy under+ // Tauri; plain fetch under web hosts that allow it).+ buffer = await (+ await this.deps.fetchAsset(media_url, { signal })+ ).arrayBuffer();+ } catch (error) {+ if ((error as { name?: string })?.name !== "AbortError") {+ console.error("load Splat from Tauri error:", error); }+ throw error;+ } + return new Promise<SplatMesh>((resolve) => { new SplatMesh({ fileBytes: buffer, onLoad: (mesh) => {@@ -32,15 +32,21 @@ export type SceneObject = { }; export interface SceneManagerAPI {- create(media_token: string, name: string, position: THREE.Vector3): void;- retrieve(object_uuid: string): void;- delete(object_uuid: string): void;+ create(+ media_token: string,+ name: string,+ position: THREE.Vector3,+ ): Promise<THREE.Object3D<THREE.Object3DEventMap> | undefined>;+ retrieve(+ object_uuid: string,+ ): Promise<THREE.Object3D<THREE.Object3DEventMap> | undefined>;+ delete(object_uuid: string): Promise<void>; update( object_uuid: string, position: THREE.Vector3, rotation: THREE.Euler, scale: THREE.Vector3,- ): void;+ ): Promise<void>; selected(): void; render_outliner(timeline_characters: { [key: string]: ClipGroup }): void; select_object(id: string): void;@@ -23,26 +23,28 @@ const scope = self as unknown as { postMessage: (message: ConvertResponse, transfer?: Transferable[]) => void; }; -scope.onmessage = async (event) => {- const { id, buffer } = event.data;- try {- const group = new FBXLoader().parse(buffer, "");- const glb = await new Promise<ArrayBuffer>((resolve, reject) => {- new GLTFExporter().parse(- group,- (result) => {- if (result instanceof ArrayBuffer) {- resolve(result);- } else {- reject(new Error("GLTF export did not produce binary output."));- }- },- (error) => reject(error),- { binary: true, animations: group.animations ?? [] },- );- });- scope.postMessage({ id, ok: true, glb }, [glb]);- } catch (error) {- scope.postMessage({ id, ok: false, error: String(error) });- }+scope.onmessage = (event) => {+ void (async () => {+ const { id, buffer } = event.data;+ try {+ const group = new FBXLoader().parse(buffer, "");+ const glb = await new Promise<ArrayBuffer>((resolve, reject) => {+ new GLTFExporter().parse(+ group,+ (result) => {+ if (result instanceof ArrayBuffer) {+ resolve(result);+ } else {+ reject(new Error("GLTF export did not produce binary output."));+ }+ },+ (error) => reject(error),+ { binary: true, animations: group.animations ?? [] },+ );+ });+ scope.postMessage({ id, ok: true, glb }, [glb]);+ } catch (error) {+ scope.postMessage({ id, ok: false, error: String(error) });+ }+ })(); };@@ -539,7 +539,7 @@ export class AudioManager { }): Promise<AudioBuffer | null> { const cacheKey = this.buildPreparedClipCacheKey({ clip }); const existing = this.preparedClipBuffers.get(cacheKey);- if (existing) {+ if (existing !== undefined) { return existing; } @@ -574,7 +574,7 @@ export class AudioManager { clip: AudioClipSource; }): Promise<AudioBuffer | null> { const existing = this.decodedBuffers.get(clip.sourceKey);- if (existing) {+ if (existing !== undefined) { return existing; } @@ -26,7 +26,7 @@ export function clearFontAtlasCache(): void { export function loadFontAtlas(): Promise<FontAtlas | null> { if (cachedAtlas) return Promise.resolve(cachedAtlas);- if (atlasFetchPromise) return atlasFetchPromise;+ if (atlasFetchPromise !== null) return atlasFetchPromise; atlasFetchPromise = fetch(FONT_ATLAS_PATH) .then(async (response) => {@@ -35,7 +35,7 @@ export function loadImageSource({ const cacheKey = `${url}::${maxSourceSize ?? "full"}`; const cached = imageSourceCache.get(cacheKey);- if (cached) return cached;+ if (cached !== undefined) return cached; const promise = (async (): Promise<CachedImageSource> => { const image = new Image();@@ -25,7 +25,7 @@ export function loadStickerSource({ stickerId: string; }): Promise<CachedStickerSource> { const cached = stickerSourceCache.get(stickerId);- if (cached) return cached;+ if (cached !== undefined) return cached; const promise = (async (): Promise<CachedStickerSource> => { const url = resolveStickerId({@@ -170,7 +170,7 @@ export class VideoCache { try { while (true) {- if (sinkData.prefetching && sinkData.prefetchPromise) {+ if (sinkData.prefetching && sinkData.prefetchPromise !== null) { await sinkData.prefetchPromise; } @@ -215,7 +215,7 @@ export class VideoCache { time: number; }): Promise<WrappedCanvas | null> { try {- if (sinkData.prefetching && sinkData.prefetchPromise) {+ if (sinkData.prefetching && sinkData.prefetchPromise !== null) { await sinkData.prefetchPromise; } @@ -27,7 +27,7 @@ export class WaveformCache { audioUrl, }: GetSourceWaveformSummaryArgs): Promise<SourceWaveformSummary> { const existing = this.summaries.get(sourceKey);- if (existing) {+ if (existing !== undefined) { return existing; }