diff --git a/SynonymGroup.ts b/SynonymGroup.ts index 8ed75d2..db08cb9 100644 --- a/SynonymGroup.ts +++ b/SynonymGroup.ts @@ -189,8 +189,8 @@ SELECT DISTINCT ?uri WHERE { } ${ infrasp - ? `?uri dwc:subspecies|dwc:variety|dwc:infraspecificEpithet "${infrasp}" .` - : "FILTER NOT EXISTS { ?uri dwc:subspecies|dwc:variety|dwc:infraspecificEpithet ?infrasp . }" + ? `?uri dwc:subSpecies|dwc:variety|dwc:form|dwc:infraspecificEpithet "${infrasp}" .` + : "FILTER NOT EXISTS { ?uri dwc:subSpecies|dwc:variety|dwc:form|dwc:infraspecificEpithet ?infrasp . }" } } LIMIT 500`; @@ -242,8 +242,8 @@ SELECT DISTINCT ?tn ?tc ?col ?rank ?genus ?species ?infrasp ?name ?authority } OPTIONAL { - ?tn a dwcFP:TaxonName . - ?tn dwc:rank ?rank . + ?tn dwc:rank ?trank . + FILTER(LCASE(?rank) = LCASE(?trank)) ?tn dwc:genus ?genus . ?tn dwc:kingdom ?kingdom . { @@ -251,10 +251,10 @@ SELECT DISTINCT ?tn ?tc ?col ?rank ?genus ?species ?infrasp ?name ?authority ?tn dwc:species ?species . { ?col dwc:infraspecificEpithet ?infrasp . - ?tn dwc:subspecies|dwc:variety ?infrasp . + ?tn dwc:subSpecies|dwc:variety|dwc:form ?infrasp . } UNION { FILTER NOT EXISTS { ?col dwc:infraspecificEpithet ?infrasp . } - FILTER NOT EXISTS { ?tn dwc:subspecies|dwc:variety ?infrasp . } + FILTER NOT EXISTS { ?tn dwc:subSpecies|dwc:variety|dwc:form ?infrasp . } } } UNION { FILTER NOT EXISTS { ?col dwc:specificEpithet ?species . } @@ -347,11 +347,12 @@ SELECT DISTINCT ?tn ?tc ?col ?rank ?genus ?species ?infrasp ?name ?authority ?tn dwc:genus ?genus . OPTIONAL { ?tn dwc:species ?species . - OPTIONAL { ?tn dwc:subspecies|dwc:variety ?infrasp . } + OPTIONAL { ?tn dwc:subSpecies|dwc:variety|dwc:form ?infrasp . } } OPTIONAL { - ?col dwc:taxonRank ?rank . + ?col dwc:taxonRank ?crank . + FILTER(LCASE(?rank) = LCASE(?crank)) OPTIONAL { ?col dwc:scientificNameAuthorship ?colAuth . } ?col dwc:scientificName ?fullName . # Note: contains authority ?col dwc:genericName ?genus . @@ -362,10 +363,10 @@ SELECT DISTINCT ?tn ?tc ?col ?rank ?genus ?species ?infrasp ?name ?authority ?tn dwc:species ?species . { ?col dwc:infraspecificEpithet ?infrasp . - ?tn dwc:subspecies|dwc:variety ?infrasp . + ?tn dwc:subSpecies|dwc:variety|dwc:form ?infrasp . } UNION { FILTER NOT EXISTS { ?col dwc:infraspecificEpithet ?infrasp . } - FILTER NOT EXISTS { ?tn dwc:subspecies|dwc:variety ?infrasp . } + FILTER NOT EXISTS { ?tn dwc:subSpecies|dwc:variety|dwc:form ?infrasp . } } } UNION { FILTER NOT EXISTS { ?col dwc:specificEpithet ?species . } @@ -452,11 +453,12 @@ SELECT DISTINCT ?tn ?tc ?col ?rank ?genus ?species ?infrasp ?name ?authority ?tn dwc:kingdom ?kingdom . OPTIONAL { ?tn dwc:species ?species . - OPTIONAL { ?tn dwc:subspecies|dwc:variety ?infrasp . } + OPTIONAL { ?tn dwc:subSpecies|dwc:variety|dwc:form ?infrasp . } } OPTIONAL { - ?col dwc:taxonRank ?rank . + ?col dwc:taxonRank ?crank . + FILTER(LCASE(?rank) = LCASE(?crank)) OPTIONAL { ?col dwc:scientificNameAuthorship ?colAuth . } ?col dwc:scientificName ?fullName . # Note: contains authority ?col dwc:genericName ?genus . @@ -467,10 +469,10 @@ SELECT DISTINCT ?tn ?tc ?col ?rank ?genus ?species ?infrasp ?name ?authority ?tn dwc:species ?species . { ?col dwc:infraspecificEpithet ?infrasp . - ?tn dwc:subspecies|dwc:variety ?infrasp . + ?tn dwc:subSpecies|dwc:variety|dwc:form ?infrasp . } UNION { FILTER NOT EXISTS { ?col dwc:infraspecificEpithet ?infrasp . } - FILTER NOT EXISTS { ?tn dwc:subspecies|dwc:variety ?infrasp . } + FILTER NOT EXISTS { ?tn dwc:subSpecies|dwc:variety|dwc:form ?infrasp . } } } UNION { FILTER NOT EXISTS { ?col dwc:specificEpithet ?species . } @@ -562,10 +564,9 @@ LIMIT 500`; for (const t of json.results.bindings) { if (t.col) { const colURI = t.col.value; - console.log(colURI); if (!authorizedCoLNames.find((e) => e.colURI === colURI)) { if (this.expanded.has(colURI)) { - console.log("Abbruch: already known", colURI); + console.log("Skipping known", colURI); return; } this.expanded.add(colURI); @@ -602,7 +603,7 @@ LIMIT 500`; cite, }; } else if (this.expanded.has(t.tc.value)) { - console.log("Abbruch: already known", t.tc.value); + console.log("Skipping known", t.tc.value); return; } else { authorizedTCNames.push({ @@ -635,6 +636,7 @@ LIMIT 500`; const name: Name = { displayName, + rank: json.results.bindings[0].rank!.value, taxonNameURI, authorizedNames: [...authorizedCoLNames, ...authorizedTCNames], justification, @@ -1044,6 +1046,8 @@ export type Name = { // kingdom: string; /** Human-readable name */ displayName: string; + /** taxonomic rank */ + rank: string; /** vernacular names */ vernacularNames: Promise; diff --git a/build_example.ts b/build_example.ts index 7e7a72f..e9b618a 100644 --- a/build_example.ts +++ b/build_example.ts @@ -1,4 +1,5 @@ import * as esbuild from "esbuild"; +import { denoPlugins } from "@luca/esbuild-deno-loader"; const SERVE = Deno.args.includes("serve"); const BUILD = Deno.args.includes("build"); @@ -9,6 +10,7 @@ const config: esbuild.BuildOptions = { sourcemap: true, bundle: true, format: "esm", + plugins: [...denoPlugins()], lineLimit: 120, minify: BUILD ? true : false, banner: SERVE diff --git a/deno.jsonc b/deno.jsonc index 1013d43..773338b 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -15,6 +15,7 @@ ] }, "imports": { + "@luca/esbuild-deno-loader": "jsr:@luca/esbuild-deno-loader@^0.11.0", "esbuild": "npm:esbuild@^0.24.0" }, "tasks": { diff --git a/deno.lock b/deno.lock index 2883292..90070a3 100644 --- a/deno.lock +++ b/deno.lock @@ -1,8 +1,31 @@ { "version": "4", "specifiers": { + "jsr:@luca/esbuild-deno-loader@0.11": "0.11.0", + "jsr:@std/bytes@^1.0.2": "1.0.2", + "jsr:@std/encoding@^1.0.5": "1.0.5", + "jsr:@std/path@^1.0.6": "1.0.7", "npm:esbuild@0.24": "0.24.0" }, + "jsr": { + "@luca/esbuild-deno-loader@0.11.0": { + "integrity": "c05a989aa7c4ee6992a27be5f15cfc5be12834cab7ff84cabb47313737c51a2c", + "dependencies": [ + "jsr:@std/bytes", + "jsr:@std/encoding", + "jsr:@std/path" + ] + }, + "@std/bytes@1.0.2": { + "integrity": "fbdee322bbd8c599a6af186a1603b3355e59a5fb1baa139f8f4c3c9a1b3e3d57" + }, + "@std/encoding@1.0.5": { + "integrity": "ecf363d4fc25bd85bd915ff6733a7e79b67e0e7806334af15f4645c569fefc04" + }, + "@std/path@1.0.7": { + "integrity": "76a689e07f0e15dcc6002ec39d0866797e7156629212b28f27179b8a5c3b33a1" + } + }, "npm": { "@esbuild/aix-ppc64@0.24.0": { "integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==" @@ -108,6 +131,7 @@ }, "workspace": { "dependencies": [ + "jsr:@luca/esbuild-deno-loader@0.11", "npm:esbuild@0.24" ] } diff --git a/example/index.css b/example/index.css index add898e..b61bbaa 100644 --- a/example/index.css +++ b/example/index.css @@ -2,6 +2,10 @@ box-sizing: border-box; } +:root { + font-family: Inter, Arial, Helvetica, sans-serif; +} + #root:empty::before { content: "You should see a list of synonyms here"; } @@ -17,11 +21,22 @@ syno-name { margin: 1rem 0; } +.rank { + font-size: 0.8rem; + line-height: 1rem; + padding: 0 0.2rem; + margin: 0.2rem 0; + border-radius: 0.2rem; + background: #ededed; + font-weight: normal; + color: #686868; +} + .uri:not(:empty) { font-size: 0.8rem; line-height: 1rem; padding: 0 0.2rem; - margin: 0.2rem; + margin: 0.2rem 0; border-radius: 0.2rem; background: #ededed; font-family: monospace; diff --git a/example/index.ts b/example/index.ts index 4fac66e..aece473 100644 --- a/example/index.ts +++ b/example/index.ts @@ -5,6 +5,7 @@ import { SynonymGroup, type Treatment, } from "../mod.ts"; +import { distinct } from "jsr:@std/collections/distinct"; const params = new URLSearchParams(document.location.search); const HIDE_COL_ONLY_SYNONYMS = !params.has("show_col"); @@ -196,6 +197,11 @@ class SynoName extends HTMLElement { title.append(name_title); this.append(title); + const rank_badge = document.createElement("span"); + rank_badge.classList.add("rank"); + rank_badge.innerText = name.rank; + title.append(" ", rank_badge); + if (name.taxonNameURI) { const name_uri = document.createElement("code"); name_uri.classList.add("taxon", "uri"); @@ -204,20 +210,21 @@ class SynoName extends HTMLElement { "", ); name_uri.title = name.taxonNameURI; - title.append(name_uri); + title.append(" ", name_uri); } const justification = document.createElement("abbr"); justification.classList.add("justification"); justification.innerText = "...?"; justify(name).then((just) => justification.title = `This ${just}`); - title.append(justification); + title.append(" ", justification); - const vernacular = document.createElement("code"); + const vernacular = document.createElement("div"); vernacular.classList.add("vernacular"); name.vernacularNames.then((names) => { if (names.size > 0) { - vernacular.innerText = "“" + [...names.values()].join("”, “") + "”"; + vernacular.innerText = "“" + + distinct([...names.values()].flat()).join("”, “") + "”"; } }); this.append(vernacular);