Merge pull request #75 from fsolla/cursor/b5-geometry-factory-ac3f

B5 — Cache CLI compartilhado + factory mun/TI (F2–F3)
This commit is contained in:
Francisco Solla 2026-07-30 22:53:55 -03:00 committed by GitHub
commit 99330f845d
5 changed files with 102 additions and 22 deletions

View file

@ -1,7 +1,7 @@
# Escala e DRY pós-B2 (geometrias + scripts CLI)
Status: Fase 1 entregue com B3 (2026-07-19); Fases 2–3 pendentes
Atualizado em: 2026-07-27 (`capture-review-debts` pós-B8+: `scripts/lib/topology.mjs` resolve por precedente onde o helper da F2 vive — `scripts/lib/`, não `src/lib/`; 2026-07-26 pós-B8 F2: 5º call site; 2026-07-20 pós-A8: `build-bahia-demographics.mjs` reforça o gatilho da F2 como 4º call site)
Status: Fases 1–3 entregues (F1 com B3 em 2026-07-19; F2 em P3-H/`scripts/lib/cli.mjs`; F3 em #28)
Atualizado em: 2026-07-31 (F3: `bahiaGeometryModuleFactory.ts` + wrappers mun/TI)
Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B, item B5)
Responsável: —

View file

@ -2,7 +2,10 @@ import type { Feature, MultiPolygon, Polygon } from 'geojson'
import type { GeometryCollection, Topology } from 'topojson-specification'
/** Every committed mesh is polygonal; only the properties differ. */
type BahiaFeature<Properties> = Feature<Polygon | MultiPolygon, Properties>
export type BahiaFeature<Properties extends Record<string, unknown>> = Feature<
Polygon | MultiPolygon,
Properties
>
type BahiaMunicipalityProperties = {
codarea: string

View file

@ -0,0 +1,75 @@
import { feature } from 'topojson-client'
import type { BahiaFeature } from '@/lib/bahiaGeometriesTypes'
import type { GeometryCollection, Topology } from 'topojson-specification'
type GeometryModuleBase<Properties extends Record<string, unknown>, TObjectName extends string> = {
topology: Topology<{ [key in TObjectName]: GeometryCollection<Properties> }>
features: readonly BahiaFeature<Properties>[]
}
type IndexedGeometryModule<
Properties extends Record<string, unknown>,
TObjectName extends string,
KeyProperty extends keyof Properties & string,
> = GeometryModuleBase<Properties, TObjectName> & {
getFeatureByKey: (key: Properties[KeyProperty]) => BahiaFeature<Properties> | undefined
}
type BuildGeometryModuleOptions<
Properties extends Record<string, unknown>,
TObjectName extends string,
KeyProperty extends keyof Properties & string,
> = {
topology: Topology<{ [key in TObjectName]: GeometryCollection<Properties> }>
objectName: TObjectName
keyProperty?: KeyProperty
}
export function buildGeometryModuleFromTopology<
Properties extends Record<string, unknown>,
TObjectName extends string,
KeyProperty extends keyof Properties & string,
>(
options: BuildGeometryModuleOptions<Properties, TObjectName, KeyProperty> & {
keyProperty: KeyProperty
},
): IndexedGeometryModule<Properties, TObjectName, KeyProperty>
export function buildGeometryModuleFromTopology<
Properties extends Record<string, unknown>,
TObjectName extends string,
>(
options: BuildGeometryModuleOptions<Properties, TObjectName, never>,
): GeometryModuleBase<Properties, TObjectName>
export function buildGeometryModuleFromTopology<
Properties extends Record<string, unknown>,
TObjectName extends string,
KeyProperty extends keyof Properties & string,
>({
topology,
objectName,
keyProperty,
}: BuildGeometryModuleOptions<Properties, TObjectName, KeyProperty>):
| GeometryModuleBase<Properties, TObjectName>
| IndexedGeometryModule<Properties, TObjectName, KeyProperty> {
const features = feature(topology, topology.objects[objectName])
.features as BahiaFeature<Properties>[]
const base: GeometryModuleBase<Properties, TObjectName> = {
topology,
features,
}
if (!keyProperty) {
return base
}
const featuresByKey = new Map(features.map((entry) => [entry.properties[keyProperty], entry]))
return {
...base,
getFeatureByKey: (key) => featuresByKey.get(key),
}
}

View file

@ -1,23 +1,23 @@
import { feature } from 'topojson-client'
import type {
BahiaMunicipalityFeature,
MunicipalityGeometryModule,
MunicipalityTopology,
} from '@/lib/bahiaGeometriesTypes'
import { buildGeometryModuleFromTopology } from '@/lib/bahiaGeometryModuleFactory'
import municipalityTopologyJson from '@/lib/geometries/bahia-municipalities.topo.json'
const topology = municipalityTopologyJson as unknown as MunicipalityTopology
const municipalityFeatures = feature(topology, topology.objects.municipalities)
.features as BahiaMunicipalityFeature[]
const municipalityByCodarea = new Map(
municipalityFeatures.map((entry) => [entry.properties.codarea, entry]),
)
const { topology, features, getFeatureByKey } = buildGeometryModuleFromTopology<
BahiaMunicipalityFeature['properties'],
'municipalities',
'codarea'
>({
topology: municipalityTopologyJson as unknown as MunicipalityTopology,
objectName: 'municipalities',
keyProperty: 'codarea',
})
export const municipalityGeometryModule: MunicipalityGeometryModule = {
topology,
features: municipalityFeatures,
getMunicipalityFeature: (codarea: string) => municipalityByCodarea.get(codarea),
features,
getMunicipalityFeature: getFeatureByKey,
}

View file

@ -1,18 +1,20 @@
import { feature } from 'topojson-client'
import type {
BahiaTerritoryFeature,
TerritoryGeometryModule,
TerritoryTopology,
} from '@/lib/bahiaGeometriesTypes'
import { buildGeometryModuleFromTopology } from '@/lib/bahiaGeometryModuleFactory'
import territoryTopologyJson from '@/lib/geometries/bahia-identity-territories.topo.json'
const topology = territoryTopologyJson as unknown as TerritoryTopology
const territoryFeatures = feature(topology, topology.objects.territories)
.features as BahiaTerritoryFeature[]
const { topology, features } = buildGeometryModuleFromTopology<
BahiaTerritoryFeature['properties'],
'territories'
>({
topology: territoryTopologyJson as unknown as TerritoryTopology,
objectName: 'territories',
})
export const territoryGeometryModule: TerritoryGeometryModule = {
topology,
features: territoryFeatures,
features,
}