mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
fix(outlines): harden shared cache and provider lifecycle
This commit is contained in:
1 parent
9559e7a282
commit
177b5951a0
27 files changed
+3363
-248
No files matched your search
@@ -420,8 +420,8 @@ const COUNTY_WORDS = [
|
||||
];
|
||||
const COUNTY_WORD_RE = new RegExp(`\\b(${COUNTY_WORDS.join('|')})\\b`);
|
||||
const STATE_PREFIX_RE =
|
||||
/^(?:free state|state|commonwealth|province|territory|prefecture|region|land|canton|department) of (.+)$/;
|
||||
const STATE_SUFFIX_RE = /^(.+) (?:state|province|prefecture|territory)$/;
|
||||
/^(free state|state|commonwealth|province|territory|prefecture|region|land|canton|department) of (.+)$/;
|
||||
const STATE_SUFFIX_RE = /^(.+) (state|province|prefecture|territory)$/;
|
||||
|
||||
/**
|
||||
* Split an ask into what it names and how.
|
||||
@@ -482,14 +482,17 @@ export function parseAdminQuery(text) {
|
||||
if (prefix)
|
||||
return {
|
||||
kind: 'state',
|
||||
name: prefix[1],
|
||||
name: prefix[2],
|
||||
qualifiers,
|
||||
postal: null,
|
||||
countyWord: null,
|
||||
full: head,
|
||||
form: 'prefix',
|
||||
adminType: prefix[1],
|
||||
};
|
||||
const suffix = STATE_SUFFIX_RE.exec(head);
|
||||
// South Africa's canonical province name is literally "Free State"; do not
|
||||
// strip its final word as though the ask explicitly named an admin type.
|
||||
const suffix = head === 'free state' ? null : STATE_SUFFIX_RE.exec(head);
|
||||
if (suffix)
|
||||
return {
|
||||
kind: 'state',
|
||||
@@ -499,6 +502,7 @@ export function parseAdminQuery(text) {
|
||||
countyWord: null,
|
||||
full: head,
|
||||
form: 'suffix',
|
||||
adminType: suffix[2],
|
||||
};
|
||||
return {
|
||||
kind: 'any',
|
||||
@@ -510,6 +514,30 @@ export function parseAdminQuery(text) {
|
||||
};
|
||||
}
|
||||
|
||||
/** Explicit wording is stronger than a stale same-name geometry. */
|
||||
function explicitStateTypeFits(entry, parsed) {
|
||||
if (!parsed.adminType) return true;
|
||||
const words = new Set(
|
||||
normalizeAdminName(entry.feature?.type)
|
||||
.split(/[^a-z]+/)
|
||||
.filter(Boolean),
|
||||
);
|
||||
const accepted =
|
||||
{
|
||||
'free state': ['state'],
|
||||
state: ['state'],
|
||||
commonwealth: ['state'],
|
||||
province: ['province'],
|
||||
territory: ['territory'],
|
||||
prefecture: ['prefecture'],
|
||||
region: ['region'],
|
||||
land: ['state'],
|
||||
canton: ['canton'],
|
||||
department: ['department', 'departamento'],
|
||||
}[parsed.adminType] || [];
|
||||
return accepted.some((word) => words.has(word));
|
||||
}
|
||||
|
||||
/** A qualifier names the unit's country ("Bavaria, Germany") or the unit
|
||||
* itself ("Washington, DC"). */
|
||||
function qualifierMatches(entry, qualifier) {
|
||||
@@ -647,6 +675,10 @@ async function stateCandidates(parsed, { allowAmbiguous = false } = {}) {
|
||||
list = list.filter((i) =>
|
||||
parsed.qualifiers.every((q) => qualifierMatches(i.entry, q)),
|
||||
);
|
||||
// Preserve explicit identity at the selector seam. In particular,
|
||||
// "Bagmati Province" must not select Natural Earth's historical NP-BA
|
||||
// Bagmati Zone merely because the point and normalized name overlap.
|
||||
list = list.filter((i) => explicitStateTypeFits(i.entry, parsed));
|
||||
if (allowAmbiguous) return list;
|
||||
// A bare name answers alone only for a prominent unit — a US state, a
|
||||
// Canadian province, Bavaria — never a French département, an English
|
||||
@@ -759,6 +791,12 @@ export async function findAdminAreaAt(names, lat, lon, scope) {
|
||||
.map(parseAdminQuery)
|
||||
.filter((p) => p?.name);
|
||||
if (!parsedList.length) return null;
|
||||
// If the ask explicitly names an admin type, do not let the geocoder's
|
||||
// untyped alias reopen an incompatible historical same-name boundary.
|
||||
const explicitStates = parsedList.filter(
|
||||
(parsed) => parsed.kind === 'state' && parsed.adminType,
|
||||
);
|
||||
const stateParses = explicitStates.length ? explicitStates : parsedList;
|
||||
const containing = (items) => {
|
||||
const out = [];
|
||||
for (const item of items)
|
||||
@@ -803,7 +841,7 @@ export async function findAdminAreaAt(names, lat, lon, scope) {
|
||||
return toResult(rank(found, { lat, lon })[0], found.length);
|
||||
}
|
||||
const states = [];
|
||||
for (const parsed of parsedList)
|
||||
for (const parsed of stateParses)
|
||||
states.push(
|
||||
...(await stateCandidates(
|
||||
{ ...parsed, qualifiers: [] },
|
||||
|
||||
@@ -225,6 +225,28 @@ test('geocoder-confirmed lookup: the named unit that contains the point', async
|
||||
assert.equal(await findAdminAreaAt(['Georgia'], 41.7, 44.8, 'state'), null);
|
||||
const newYork = await findAdminAreaAt(['New York'], 42.9, -75.5, 'state');
|
||||
assert.equal(newYork?.id, 'US-NY');
|
||||
assert.equal(
|
||||
(
|
||||
await findAdminAreaAt(
|
||||
['Ontario Province', 'Ontario'],
|
||||
43.6532,
|
||||
-79.3832,
|
||||
'state',
|
||||
)
|
||||
)?.id,
|
||||
'CA-ON',
|
||||
);
|
||||
// Natural Earth still carries the historical NP-BA Bagmati Zone. An ask
|
||||
// for today's province must not silently select that incompatible geometry.
|
||||
assert.equal(
|
||||
await findAdminAreaAt(
|
||||
['Bagmati Province', 'Bagmati'],
|
||||
27.7172,
|
||||
85.324,
|
||||
'state',
|
||||
),
|
||||
null,
|
||||
);
|
||||
// A county the geocoder typed, named without the county word.
|
||||
const travis = await findAdminAreaAt(
|
||||
['Travis', 'Travis County'],
|
||||
|
||||
@@ -26,6 +26,10 @@ import {
|
||||
|
||||
const PLACES = new URL('./local_data/us_census_places/', import.meta.url);
|
||||
const WOF = new URL('./local_data/wof_neighborhoods/', import.meta.url);
|
||||
const WOF_LICENSES = new URL(
|
||||
'../../scripts/wof-open-licenses.json',
|
||||
import.meta.url,
|
||||
);
|
||||
const readJson = (url) => JSON.parse(readFileSync(url, 'utf8'));
|
||||
|
||||
const AUSTIN = { lat: 30.2672, lon: -97.7431 };
|
||||
@@ -365,15 +369,71 @@ test('places pack: every state file, unique ids, sane and valid rings', () => {
|
||||
assert.equal(total, 32_629);
|
||||
});
|
||||
|
||||
const UNSTATED = /assumed|unknown|unresolved|n\/a/i;
|
||||
const WOF_LICENSE_POLICY = readJson(WOF_LICENSES);
|
||||
const ALLOWED_WOF_LICENSES = new Set(WOF_LICENSE_POLICY.licenses);
|
||||
const licenceAllowed = (value) =>
|
||||
typeof value === 'string' && ALLOWED_WOF_LICENSES.has(value);
|
||||
|
||||
test('neighborhood pack ships only sources whose licence is stated', () => {
|
||||
test('the WOF licence policy accepts only exact reviewed registry strings', () => {
|
||||
for (const accepted of WOF_LICENSE_POLICY.licenses)
|
||||
assert.equal(licenceAllowed(accepted), true, accepted);
|
||||
for (const rejected of [
|
||||
'',
|
||||
null,
|
||||
0,
|
||||
'Unknown',
|
||||
'Restricted',
|
||||
'CC BY-NC 4.0',
|
||||
'CC BY-SA 4.0',
|
||||
'CC BY 5.0 (unreviewed)',
|
||||
'CC BY Restricted',
|
||||
'CC BY Unknown',
|
||||
'Creative Commons NonCommercial',
|
||||
'ODbL 1.0',
|
||||
'cc by 4.0',
|
||||
'CC BY 4.0 ',
|
||||
' CC BY 4.0',
|
||||
'CC BY 4.0',
|
||||
'CC\tBY 4.0',
|
||||
])
|
||||
assert.equal(licenceAllowed(rejected), false, JSON.stringify(rejected));
|
||||
});
|
||||
|
||||
test('the Zetashapes raw registry spelling is admitted by pinned provenance', () => {
|
||||
const review = WOF_LICENSE_POLICY.reviewedSources.zs;
|
||||
assert.deepEqual(
|
||||
{
|
||||
name: review.name,
|
||||
registryCommit: review.registryCommit,
|
||||
registrySha256: review.registrySha256,
|
||||
rawLicenseType: review.rawLicenseType,
|
||||
licenseTextSha256: review.licenseTextSha256,
|
||||
},
|
||||
{
|
||||
name: 'Zetashapes',
|
||||
registryCommit: 'e17af153c144fe6e08aa8db2607b4bf8aecd448d',
|
||||
registrySha256:
|
||||
'd8a5dd873d26eee11583de4438185c046dec33848d5bde27047ca4bff44d9c39',
|
||||
rawLicenseType: 'Public domain',
|
||||
licenseTextSha256:
|
||||
'91757f96f74f6dfb4a7206486b78586da0d039e9611e224fc793c7167dcfe615',
|
||||
},
|
||||
);
|
||||
assert.equal(licenceAllowed(review.rawLicenseType), true);
|
||||
assert.match(review.decision, /TIGER\/Line/);
|
||||
assert.match(review.decision, /Flickr/);
|
||||
});
|
||||
|
||||
test('neighborhood pack ships only explicitly allowed and credited sources', () => {
|
||||
const index = readJson(new URL('index.json', WOF));
|
||||
const sources = index.meta.sources;
|
||||
const credits = readFileSync(new URL('ATTRIBUTION.md', WOF), 'utf8');
|
||||
for (const [key, source] of Object.entries(sources)) {
|
||||
assert.ok(source.license, `${key} has a licence`);
|
||||
assert.doesNotMatch(source.license, UNSTATED, key);
|
||||
assert.equal(
|
||||
licenceAllowed(source.license),
|
||||
true,
|
||||
`${key}: ${source.license}`,
|
||||
);
|
||||
assert.notEqual(key, 'unknown');
|
||||
assert.ok(credits.includes(`\`${key}\``), `${key} credited`);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user