@developmentseed/epsg 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # @developmentseed/epsg
2
+
3
+ The full EPSG projection database, compressed to **309kb** for the web.
4
+
5
+ [EPSG]: https://en.wikipedia.org/wiki/EPSG_Geodetic_Parameter_Dataset
6
+
7
+ Some existing EPSG amalgamations exist, but all are uncompressed, incomplete, outdated, and/or not reproducible [^1] [^2] [^3] [^4]. This package uses the [DecompressionStream] API, now [widely available in browsers][DecompressionStream_gzip], to bundle a gzip-compressed text file of WKT definitions for **all 7352 defined EPSG projection codes**.
8
+
9
+ [DecompressionStream]: https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream
10
+ [DecompressionStream_gzip]: https://caniuse.com/mdn-api_decompressionstream_decompressionstream_gzip
11
+
12
+ [^1]: [`epsg`](https://www.npmjs.com/package/epsg) includes only 3912 definitions, stores older, deprecated proj strings, and is uncompressed, coming to 500kb.
13
+
14
+ [^2]: [`epsg-index`](https://www.npmjs.com/package/epsg-index) stores extra parsed information for each projection and is **7.7 MB**.
15
+
16
+ [^3]: [`proj4-list`](https://www.npmjs.com/package/proj4-list) includes only 5434 definitions, stores older, deprecated proj strings, and is 759KB of uncompressed strings.
17
+
18
+ [^4]: [`@esri/proj-codes`](https://www.npmjs.com/package/@esri/proj-codes) ships a lot of redundant information, coming to nearly **15MB** of JSON.
19
+
20
+ ## Usage
21
+
22
+ Currently, the only package entrypoint is `@developmentseed/epsg/all`, which loads a `Map<number, string>`, with all EPSG definitions in OGC WKT2 format.
23
+
24
+ ```ts
25
+ import loadEPSG from "@developmentseed/epsg/all";
26
+ import proj4 from "proj4";
27
+
28
+ // Load the EPSG database
29
+ const epsg = await loadEPSG();
30
+
31
+ // Access WKT strings by EPSG code.
32
+ const wkt4326 = epsg.get(4326);
33
+ const wkt3857 = epsg.get(3857);
34
+
35
+ // Then use proj4.js as normal
36
+ const converter = proj4(wkt4326, wkt3857);
37
+ const inputPoint = [1, 52];
38
+ const outputPoint = converter.forward(inputPoint);
39
+ ```
40
+
41
+ ## Generate new EPSG definitions
42
+
43
+ First, download the latest EPSG definitions in WKT format. Go to [epsg.org/download-dataset.html](https://epsg.org/download-dataset.html), create an account or log in, then download the `WKT File` version.
44
+
45
+ Then, from this directory, run
46
+
47
+ ```bash
48
+ python scripts/generate.py
49
+ ```
50
+
51
+ Then the file `src/all.csv.gz` will be updated with the latest EPSG definitions.
52
+
53
+ ## Publishing
54
+
55
+ The `build` script in `package.json` will automatically include `all.csv.gz` in the published NPM package.
56
+
57
+ If you get an error like
58
+
59
+ > `cp: dist/all.csv.gz: No such file or directory`
60
+
61
+ You may need to delete an errant `tsconfig.build.tsbuildinfo` and try again. I'm not sure why.
62
+
Binary file
package/dist/all.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Load the EPSG database into memory.
3
+ *
4
+ * The database is stored as a gzipped CSV file. This function loads and parses
5
+ * the file, returning a map of EPSG code to WKT string.
6
+ *
7
+ * The result is cached after the first call, so subsequent calls will return
8
+ * the cached result.
9
+ *
10
+ * @param url - Optional URL to the gzipped CSV file. When using a bundler like
11
+ * Vite, pass the asset URL directly to ensure correct resolution:
12
+ * `import csvUrl from "@developmentseed/epsg/all.csv.gz?url"`
13
+ */
14
+ export default function loadEPSG(url?: string | URL): Promise<Map<number, string>>;
15
+ //# sourceMappingURL=all.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"all.d.ts","sourceRoot":"","sources":["../src/all.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC9B,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,GACjB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAM9B"}
package/dist/all.js ADDED
@@ -0,0 +1,73 @@
1
+ const SEP = "|";
2
+ /** A cached promise for the loaded EPSG database */
3
+ let cachedLoad = null;
4
+ /**
5
+ * Load the EPSG database into memory.
6
+ *
7
+ * The database is stored as a gzipped CSV file. This function loads and parses
8
+ * the file, returning a map of EPSG code to WKT string.
9
+ *
10
+ * The result is cached after the first call, so subsequent calls will return
11
+ * the cached result.
12
+ *
13
+ * @param url - Optional URL to the gzipped CSV file. When using a bundler like
14
+ * Vite, pass the asset URL directly to ensure correct resolution:
15
+ * `import csvUrl from "@developmentseed/epsg/all.csv.gz?url"`
16
+ */
17
+ export default function loadEPSG(url) {
18
+ if (!cachedLoad) {
19
+ cachedLoad = load(url ?? new URL("./all.csv.gz", import.meta.url));
20
+ }
21
+ return cachedLoad;
22
+ }
23
+ async function load(url) {
24
+ const response = await fetch(url);
25
+ if (!response.body) {
26
+ throw new Error("Response has no body");
27
+ }
28
+ // When the server serves the gzipped file with `Content-Encoding: gzip`, the
29
+ // browser automatically decompresses it, so we can just read the text
30
+ // directly.
31
+ // If the header is missing, we need to decompress it ourselves.
32
+ const alreadyDecompressed = response.headers.get("Content-Encoding") === "gzip";
33
+ const stream = !alreadyDecompressed
34
+ ? response.body
35
+ .pipeThrough(new DecompressionStream("gzip"))
36
+ .pipeThrough(new TextDecoderStream())
37
+ : response.body.pipeThrough(new TextDecoderStream());
38
+ return parseStream(stream);
39
+ }
40
+ async function parseStream(stream) {
41
+ const reader = stream.getReader();
42
+ const map = new Map();
43
+ let buffer = "";
44
+ while (true) {
45
+ // Read the next chunk from the stream
46
+ const { value, done } = await reader.read();
47
+ if (done) {
48
+ break;
49
+ }
50
+ buffer += value;
51
+ // The position of the newline character
52
+ let newlineIndex = buffer.indexOf("\n");
53
+ // Iterate over each line in the buffer
54
+ while (newlineIndex !== -1) {
55
+ const line = buffer.slice(0, newlineIndex);
56
+ // Update buffer range and search for next newline
57
+ buffer = buffer.slice(newlineIndex + 1);
58
+ newlineIndex = buffer.indexOf("\n");
59
+ if (!line) {
60
+ continue;
61
+ }
62
+ const sep = line.indexOf(SEP);
63
+ if (sep === -1) {
64
+ throw new Error(`Invalid line, missing separator: ${line}`);
65
+ }
66
+ const code = Number.parseInt(line.slice(0, sep), 10);
67
+ const wkt = line.slice(sep + 1);
68
+ map.set(code, wkt);
69
+ }
70
+ }
71
+ return map;
72
+ }
73
+ //# sourceMappingURL=all.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"all.js","sourceRoot":"","sources":["../src/all.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@developmentseed/epsg",
3
+ "version": "0.1.0",
4
+ "description": "The full EPSG projection database, compressed to 309kb for the web.",
5
+ "type": "module",
6
+ "exports": {
7
+ "./all": {
8
+ "types": "./dist/all.d.ts",
9
+ "default": "./dist/all.js"
10
+ },
11
+ "./all.csv.gz": "./dist/all.csv.gz"
12
+ },
13
+ "sideEffects": false,
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc --build tsconfig.build.json && cp src/all.csv.gz dist/all.csv.gz",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest",
21
+ "typecheck": "tsc --noEmit",
22
+ "prepublishOnly": "npm run build"
23
+ },
24
+ "keywords": [
25
+ "proj4",
26
+ "geotiff",
27
+ "zarr",
28
+ "cog",
29
+ "cloud-optimized-geotiff",
30
+ "raster",
31
+ "visualization",
32
+ "webgl",
33
+ "gpu"
34
+ ],
35
+ "author": "Development Seed",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/developmentseed/deck.gl-raster.git"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^25.3.3",
43
+ "jsdom": "^27.4.0",
44
+ "proj4": "^2.20.3",
45
+ "typescript": "^5.9.3",
46
+ "vitest": "^4.0.18"
47
+ },
48
+ "volta": {
49
+ "extends": "../../package.json"
50
+ }
51
+ }