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
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 120

[*.md]
trim_trailing_whitespace = false
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ jobs:
- name: Install dependencies
run: yarn

- name: Check formatting
run: yarn format:check

- name: Check for circular dependencies and print porting order
run: |
python3 analyze_imports.py modules
Expand Down
25 changes: 25 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
dist/
build/
node_modules/
coverage/
.yarn/
.pytest_cache/
debug-scripts/
yarn.lock
package-lock.json

# Generated/data JSON (treat as fixtures, not code)
tests/**/*.json

# Website build output
website/build/
website/.docusaurus/

# Auto-generated docs
docs/api-reference/

# Other languages / non-JS files
*.py
*.rs
*.md
*.parquet
12 changes: 12 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "as-needed",
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid",
"endOfLine": "lf"
}
38 changes: 38 additions & 0 deletions .zed/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"format_on_save": "on",
"formatter": {
"external": {
"command": "node_modules/.bin/prettier",
"arguments": ["--stdin-filepath", "{buffer_path}"]
}
},
"languages": {
"TypeScript": {
"format_on_save": "on",
"formatter": {
"external": {
"command": "node_modules/.bin/prettier",
"arguments": ["--stdin-filepath", "{buffer_path}"]
}
}
},
"JavaScript": {
"format_on_save": "on",
"formatter": {
"external": {
"command": "node_modules/.bin/prettier",
"arguments": ["--stdin-filepath", "{buffer_path}"]
}
}
},
"JSON": {
"format_on_save": "on",
"formatter": {
"external": {
"command": "node_modules/.bin/prettier",
"arguments": ["--stdin-filepath", "{buffer_path}"]
}
}
}
}
}
9 changes: 9 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ yarn test --run
yarn build
```

## Formatting

This project uses [Prettier](https://prettier.io/) for code formatting. The config in `.prettierrc.json` is the source of truth; editors that respect Prettier (Zed, VS Code, JetBrains, vim plugins) will pick it up automatically.

```bash
yarn format # format all files in place
yarn format:check # exit non-zero if any file would be reformatted (CI use)
```

## Generate fixtures

```bash
Expand Down
17 changes: 3 additions & 14 deletions docs/table-of-contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
{
"type": "category",
"label": "Overview",
"items": [
"README",
"motivation"
]
"items": ["README", "motivation"]
},
{
"type": "category",
Expand All @@ -21,11 +18,7 @@
{
"type": "category",
"label": "Recipes",
"items": [
"recipes/README",
"recipes/a5-vs-h3",
"recipes/paris-restaurant-density"
]
"items": ["recipes/README", "recipes/a5-vs-h3", "recipes/paris-restaurant-density"]
},
{
"type": "category",
Expand Down Expand Up @@ -53,10 +46,6 @@
{
"type": "category",
"label": "Ecosystem",
"items": [
"ecosystem/README",
"ecosystem/podcasts-and-talks",
"ecosystem/polyglot-mirroring"
]
"items": ["ecosystem/README", "ecosystem/podcasts-and-talks", "ecosystem/polyglot-mirroring"]
}
]
25 changes: 13 additions & 12 deletions examples/cli/aggregate/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { parse } = require('csv-parse/sync');
const { lonLatToCell, cellToLonLat, u64ToHex } = require('../../../dist/a5.cjs');
const {parse} = require('csv-parse/sync');
const {lonLatToCell, cellToLonLat, u64ToHex} = require('../../../dist/a5.cjs');
const fs = require('fs');

// Read and parse the CSV file
Expand All @@ -22,7 +22,7 @@ if (outputFormat !== 'json' && outputFormat !== 'parquet') {

async function writeParquet(aggregatedData, outputPath) {
// Import parquet writer functions
const { parquetWrite, schemaFromColumnData, fileWriter } = await import('hyparquet-writer');
const {parquetWrite, schemaFromColumnData, fileWriter} = await import('hyparquet-writer');

// Prepare data arrays
const cellIds = [];
Expand All @@ -35,8 +35,8 @@ async function writeParquet(aggregatedData, outputPath) {
}

const columnData = [
{ name: 'a5', data: cellIds },
{ name: 'count', data: counts }
{name: 'a5', data: cellIds},
{name: 'count', data: counts}
];

// Create file writer
Expand All @@ -53,10 +53,10 @@ async function writeParquet(aggregatedData, outputPath) {
name: 'a5',
type: 'INT64',
converted_type: 'UINT_64',
repetition_type: 'REQUIRED',
},
},
}),
repetition_type: 'REQUIRED'
}
}
})
});

const fileSize = fs.statSync(outputPath).size;
Expand Down Expand Up @@ -98,7 +98,9 @@ async function main() {
}
}

console.log(`Successfully processed ${records.length} points into ${aggregatedData.size} A5 cells at resolution ${resolution}`);
console.log(
`Successfully processed ${records.length} points into ${aggregatedData.size} A5 cells at resolution ${resolution}`
);

// Write output in requested format
if (outputFormat === 'parquet') {
Expand All @@ -110,11 +112,10 @@ async function main() {
fs.writeFileSync(outputFile, JSON.stringify(result, null, 2));
console.log(`Output written to ${outputFile}`);
}

} catch (error) {
console.error('Error processing data:', error);
process.exit(1);
}
}

main();
main();
45 changes: 20 additions & 25 deletions examples/cli/compact/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,13 @@ function parseArgs() {
}

// Validate required arguments
if (options.lon === null || options.lat === null || options.radius === null ||
options.resolution === null || !options.output) {
if (
options.lon === null ||
options.lat === null ||
options.radius === null ||
options.resolution === null ||
!options.output
) {
console.error('Error: Missing required arguments\n');
printUsage();
process.exit(1);
Expand Down Expand Up @@ -97,7 +102,7 @@ function generatePointsInRadius(centerLonLat, radiusKm, spacingMeters) {
// Convert radius to approximate degrees
// At the given latitude, calculate degrees per km
const latDegreesPerKm = 1 / 111;
const lonDegreesPerKm = 1 / (111 * Math.cos(centerLat * Math.PI / 180));
const lonDegreesPerKm = 1 / (111 * Math.cos((centerLat * Math.PI) / 180));

const radiusDegLat = radiusKm * latDegreesPerKm;
const radiusDegLon = radiusKm * lonDegreesPerKm;
Expand All @@ -121,10 +126,7 @@ function generatePointsInRadius(centerLonLat, radiusKm, spacingMeters) {
// Check if point is within radius (simple Euclidean approximation)
const dLat = lat - centerLat;
const dLon = lon - centerLon;
const distKm = Math.sqrt(
(dLat / latDegreesPerKm) ** 2 +
(dLon / lonDegreesPerKm) ** 2
);
const distKm = Math.sqrt((dLat / latDegreesPerKm) ** 2 + (dLon / lonDegreesPerKm) ** 2);

if (distKm <= radiusKm) {
points.push([lon, lat]);
Expand Down Expand Up @@ -169,7 +171,7 @@ function generateCells(centerLonLat, radiusKm, resolution) {
console.log(` Compacted to: ${compacted.length} cells`);
console.log(` Compression ratio: ${(cells.length / compacted.length).toFixed(2)}x`);

return { uncompacted: cells, compacted };
return {uncompacted: cells, compacted};
}

/**
Expand All @@ -179,14 +181,12 @@ async function writeParquet(cells, outputPath) {
const parquetPath = `${outputPath}.parquet`;

// Ensure all values are BigInt (some might be plain numbers)
const cellIds = cells.map(id => typeof id === 'bigint' ? id : BigInt(id));
const cellIds = cells.map(id => (typeof id === 'bigint' ? id : BigInt(id)));

// Import parquet writer functions
const { ByteWriter, parquetWrite, schemaFromColumnData, fileWriter } = await import('hyparquet-writer');
const {ByteWriter, parquetWrite, schemaFromColumnData, fileWriter} = await import('hyparquet-writer');

const columnData = [
{ name: 'cell_id', data: cellIds }
];
const columnData = [{name: 'cell_id', data: cellIds}];

// Create file writer
const writer = fileWriter(parquetPath);
Expand All @@ -203,10 +203,10 @@ async function writeParquet(cells, outputPath) {
name: 'cell_id',
type: 'INT64',
converted_type: 'UINT_64',
repetition_type: 'REQUIRED',
},
},
}),
repetition_type: 'REQUIRED'
}
}
})
});

const fileSize = fs.statSync(parquetPath).size;
Expand All @@ -227,7 +227,7 @@ function writeGeoJSON(cells, outputPath) {
const cellIdHex = u64ToHex(cellId);
const boundary = cellToBoundary(cellId, {
closedRing: true,
segments: 10,
segments: 10
});

features.push({
Expand All @@ -242,7 +242,7 @@ function writeGeoJSON(cells, outputPath) {

const geojson = {
type: 'FeatureCollection',
features,
features
};

fs.writeFileSync(geojsonPath, JSON.stringify(geojson, null, 2));
Expand All @@ -261,11 +261,7 @@ async function main() {
console.log(` Resolution: ${options.resolution}\n`);

// Generate cells (both uncompacted and compacted)
const { uncompacted, compacted } = generateCells(
[options.lon, options.lat],
options.radius,
options.resolution
);
const {uncompacted, compacted} = generateCells([options.lon, options.lat], options.radius, options.resolution);

// Choose which cells to output
const cellsToOutput = options.uncompacted ? uncompacted : compacted;
Expand All @@ -279,7 +275,6 @@ async function main() {
}

console.log('\n✓ Generation complete!');

} catch (error) {
console.error('Error:', error.message);
process.exit(1);
Expand Down
12 changes: 7 additions & 5 deletions examples/cli/country-polygons/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ function parseArgs() {
else if (a === '--output') opts.output = args[++i];
else if (a === '--resolution') opts.resolution = parseInt(args[++i]);
else if (a === '--help' || a === '-h') {
console.log(`Usage: node index.js [--input <geojson>] [--output <parquet>] [--resolution <n>]\n\nDefaults:\n --input ${DEFAULT_INPUT}\n --output ${DEFAULT_OUTPUT}\n --resolution ${DEFAULT_RESOLUTION}\n`);
console.log(
`Usage: node index.js [--input <geojson>] [--output <parquet>] [--resolution <n>]\n\nDefaults:\n --input ${DEFAULT_INPUT}\n --output ${DEFAULT_OUTPUT}\n --resolution ${DEFAULT_RESOLUTION}\n`
);
process.exit(0);
} else {
console.error(`Unknown option: ${a}`);
Expand Down Expand Up @@ -90,7 +92,7 @@ async function main() {
const {parquetWrite, schemaFromColumnData, fileWriter} = await import('hyparquet-writer');
const columnData = [
{name: 'cell_id', data: cellIds},
{name: 'color', data: colors},
{name: 'color', data: colors}
];
const writer = fileWriter(opts.output);
parquetWrite({
Expand All @@ -99,9 +101,9 @@ async function main() {
schema: schemaFromColumnData({
columnData,
schemaOverrides: {
cell_id: {name: 'cell_id', type: 'INT64', converted_type: 'UINT_64', repetition_type: 'REQUIRED'},
},
}),
cell_id: {name: 'cell_id', type: 'INT64', converted_type: 'UINT_64', repetition_type: 'REQUIRED'}
}
})
});

const size = fs.statSync(opts.output).size;
Expand Down
Loading
Loading