Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions .github/scripts/compare-types/packages/firestore/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,6 @@ const config: PackageConfig = {
'Type used with setIndexConfiguration. Not implemented in RN Firebase ' +
'as setIndexConfiguration is not supported.',
},
{
name: 'ListenSource',
reason:
'Union type for snapshot listener source (default, server, cache). ' +
'Not yet implemented in RN Firebase; listeners always use default behaviour.',
},
{
name: 'MemoryCacheSettings',
reason:
Expand Down Expand Up @@ -320,12 +314,6 @@ const config: PackageConfig = {
'firebase-js-sdk public type. These are structural artifacts of the ' +
'RN implementation.',
},
{
name: 'SnapshotListenOptions',
reason:
'The firebase-js-sdk includes an optional `source` property (of type ' +
'`ListenSource`) which is not yet supported in RN Firebase.',
},
// --- Wrapper classes (same public API, different structure: getters vs properties, readonly, toJSON/fromJSON) ---
{
name: 'DocumentReference',
Expand Down
3 changes: 2 additions & 1 deletion .github/scripts/compare-types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
*
* Exit codes:
* 0 — all differences are documented in the package config files
* 1 — undocumented differences found (or a required file is missing)
* 1 — undocumented differences, stale registry entries in config (resolved
* APIs still listed as missing/extra/different), or a required file missing
*/

import fs from 'fs';
Expand Down
101 changes: 77 additions & 24 deletions .github/scripts/compare-types/src/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,71 @@ function printSection(
}
}

// ---------------------------------------------------------------------------
// Stale registry (documented differences that no longer apply)
// ---------------------------------------------------------------------------

function countStale(result: ComparisonResult): number {
return (
result.staleConfigMissing.length +
result.staleConfigExtra.length +
result.staleConfigDifferentShape.length
);
}

/**
* Prints stale `config.ts` entries and returns how many were printed.
* These must run even when there are zero live diffs, otherwise a resolved
* API (e.g. an export removed from `missingInRN` in reality) would never
* force updating the comparison registry.
*/
function printStaleRegistrySection(result: ComparisonResult): number {
const totalStale = countStale(result);
if (totalStale === 0) {
return 0;
}

console.log(`\n ${c(RED, `Stale registry / config entries`)} (${totalStale}):`);

for (const name of result.staleConfigMissing) {
console.log(
`${c(RED, ' ✗')} ${c(BOLD, name)}${c(RED, ' [STALE missingInRN]')}${c(
DIM,
` — ${name} exists in React Native Firebase but is still listed under missingInRN in config.ts; remove it or reclassify (e.g. differentShape) if types still differ.`,
)}`,
);
}

for (const name of result.staleConfigExtra) {
console.log(
`${c(RED, ' ✗')} ${c(BOLD, name)}${c(RED, ' [STALE extraInRN]')}${c(
DIM,
` — ${name} is no longer an extra export in React Native Firebase but is still listed under extraInRN; remove from config.ts.`,
)}`,
);
}

for (const name of result.staleConfigDifferentShape) {
console.log(
`${c(RED, ' ✗')} ${c(BOLD, name)}${c(RED, ' [STALE differentShape]')}${c(
DIM,
` — ${name} now matches the firebase-js-sdk shape; remove from differentShape in config.ts.`,
)}`,
);
}

return totalStale;
}

// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------

/**
* Print a human-readable report to stdout.
*
* @returns `true` if there are any undocumented differences (CI failure).
* @returns `true` if there are undocumented differences or stale registry
* entries (CI failure).
*/
export function printReport(results: ComparisonResult[]): boolean {
console.log(
Expand All @@ -72,11 +129,22 @@ export function printReport(results: ComparisonResult[]): boolean {
result.extra.length +
result.differentShape.length;

if (totalDiffs === 0) {
const totalStale = countStale(result);

if (totalDiffs === 0 && totalStale === 0) {
console.log(c(GREEN, ' ✓ No differences found'));
continue;
}

if (totalDiffs === 0 && totalStale > 0) {
console.log(
c(
GREEN,
' ✓ Exported types match the firebase-js-sdk snapshot (no live diffs)',
),
);
}

// --- Missing ---
if (result.missing.length > 0) {
printSection(
Expand Down Expand Up @@ -117,42 +185,27 @@ export function printReport(results: ComparisonResult[]): boolean {
);
}

// --- Stale config entries ---
const totalStale =
result.staleConfigMissing.length +
result.staleConfigExtra.length +
result.staleConfigDifferentShape.length;

if (totalStale > 0) {
const staleNames = [
...result.staleConfigMissing,
...result.staleConfigExtra,
...result.staleConfigDifferentShape,
];
console.log(`\n ${c(RED, `Stale config entries`)} (${totalStale}):`);
for (const name of staleNames) {
console.log(
`${c(RED, ' ✗')} ${c(BOLD, name)}${c(RED, ' [STALE]')}${c(DIM, ' — now matches the firebase-js-sdk; remove from config.ts')}`,
);
}
}
const printedStale = printStaleRegistrySection(result);

// --- Summary ---
const totalUndoc =
result.undocumentedMissing.length +
result.undocumentedExtra.length +
result.undocumentedDifferentShape.length;

if (totalUndoc > 0 || totalStale > 0) {
if (totalUndoc > 0 || printedStale > 0) {
hasFailures = true;
if (totalUndoc > 0) {
console.log(
`\n ${c(RED, `✗ ${totalUndoc} undocumented difference(s) — add them to config.ts with a reason`)}`,
);
}
if (totalStale > 0) {
if (printedStale > 0) {
console.log(
`\n ${c(RED, `✗ ${totalStale} stale config entry/entries — remove them from config.ts`)}`,
`\n ${c(
RED,
`✗ ${printedStale} stale registry entry/entries — update packages/<name>/config.ts for the type comparison tool`,
)}`,
);
}
} else {
Expand Down
30 changes: 30 additions & 0 deletions packages/firestore/__tests__/firestore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import FirebaseModule from '../../app/lib/internal/FirebaseModule';
import Query from '../lib/FirestoreQuery';
// @ts-ignore test
import FirestoreDocumentSnapshot from '../lib/FirestoreDocumentSnapshot';
import { parseSnapshotArgs } from '../lib/utils';
// @ts-ignore test
import * as nativeModule from '@react-native-firebase/app/dist/module/internal/nativeModuleAndroidIos';

Expand Down Expand Up @@ -499,6 +500,35 @@ describe('Firestore', function () {
});
});
});

describe('onSnapshot()', function () {
it("accepts { source: 'cache' } listener options", function () {
const parsed = parseSnapshotArgs([{ source: 'cache' }, () => {}]);

expect(parsed.snapshotListenOptions).toEqual({
includeMetadataChanges: false,
source: 'cache',
});
});

it("accepts { source: 'default', includeMetadataChanges: true } listener options", function () {
const parsed = parseSnapshotArgs([
{ source: 'default', includeMetadataChanges: true },
() => {},
]);

expect(parsed.snapshotListenOptions).toEqual({
includeMetadataChanges: true,
source: 'default',
});
});

it("throws for unsupported listener source value 'server'", function () {
expect(() =>
parseSnapshotArgs([{ source: 'server' as 'default' | 'cache' }, () => {}]),
).toThrow("'options' SnapshotOptions.source must be one of 'default' or 'cache'.");
});
});
});

describe('modular', function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,8 @@ private void handleQueryOnSnapshot(
int listenerId,
ReadableMap listenerOptions) {
MetadataChanges metadataChanges;
SnapshotListenOptions.Builder snapshotListenOptionsBuilder =
new SnapshotListenOptions.Builder();

if (listenerOptions != null
&& listenerOptions.hasKey("includeMetadataChanges")
Expand All @@ -355,6 +357,15 @@ private void handleQueryOnSnapshot(
} else {
metadataChanges = MetadataChanges.EXCLUDE;
}
snapshotListenOptionsBuilder.setMetadataChanges(metadataChanges);

if (listenerOptions != null
&& listenerOptions.hasKey("source")
&& "cache".equals(listenerOptions.getString("source"))) {
snapshotListenOptionsBuilder.setSource(ListenSource.CACHE);
} else {
snapshotListenOptionsBuilder.setSource(ListenSource.DEFAULT);
}

final EventListener<QuerySnapshot> listener =
(querySnapshot, exception) -> {
Expand All @@ -371,7 +382,7 @@ private void handleQueryOnSnapshot(
};

ListenerRegistration listenerRegistration =
firestoreQuery.query.addSnapshotListener(metadataChanges, listener);
firestoreQuery.query.addSnapshotListener(snapshotListenOptionsBuilder.build(), listener);

collectionSnapshotListeners.put(listenerId, listenerRegistration);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,27 @@ public void documentOnSnapshot(
}
};

MetadataChanges metadataChanges;
SnapshotListenOptions.Builder snapshotListenOptionsBuilder =
new SnapshotListenOptions.Builder();

if (listenerOptions != null
&& listenerOptions.hasKey("includeMetadataChanges")
&& listenerOptions.getBoolean("includeMetadataChanges")) {
metadataChanges = MetadataChanges.INCLUDE;
snapshotListenOptionsBuilder.setMetadataChanges(MetadataChanges.INCLUDE);
} else {
metadataChanges = MetadataChanges.EXCLUDE;
snapshotListenOptionsBuilder.setMetadataChanges(MetadataChanges.EXCLUDE);
}

if (listenerOptions != null
&& listenerOptions.hasKey("source")
&& "cache".equals(listenerOptions.getString("source"))) {
snapshotListenOptionsBuilder.setSource(ListenSource.CACHE);
} else {
snapshotListenOptionsBuilder.setSource(ListenSource.DEFAULT);
}

ListenerRegistration listenerRegistration =
documentReference.addSnapshotListener(metadataChanges, listener);
documentReference.addSnapshotListener(snapshotListenOptionsBuilder.build(), listener);

documentSnapshotListeners.put(listenerId, listenerRegistration);
}
Expand Down
Loading
Loading