mapshaper 0.7.8 → 0.7.9
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/mapshaper.js +167 -22
- package/package.json +4 -2
- package/www/ai-config.js +62 -0
- package/www/geoparquet.js +9784 -2568
- package/www/mapshaper-gui.js +144 -1
- package/www/mapshaper.js +167 -22
package/mapshaper.js
CHANGED
|
@@ -25683,52 +25683,71 @@ ${svg}
|
|
|
25683
25683
|
}
|
|
25684
25684
|
|
|
25685
25685
|
var writerPromise = null;
|
|
25686
|
+
var zstdPromise = null;
|
|
25686
25687
|
var dynamicImportModule$1 = Function('id', 'return import(id)');
|
|
25687
25688
|
|
|
25688
25689
|
async function exportGeoParquet(dataset, opts, filenameOverride) {
|
|
25689
25690
|
var writer = await loadGeoParquetWriter();
|
|
25691
|
+
var compression = await getGeoParquetCompression(opts);
|
|
25690
25692
|
var extension = opts.extension || 'parquet';
|
|
25693
|
+
var files = [];
|
|
25691
25694
|
if (opts.file) {
|
|
25692
25695
|
extension = getFileExtension(opts.file) || extension;
|
|
25693
25696
|
}
|
|
25694
|
-
|
|
25695
|
-
if (!lyr.geometry_type) {
|
|
25696
|
-
stop$1('GeoParquet export requires a geometry layer');
|
|
25697
|
-
}
|
|
25697
|
+
dataset.layers.forEach(function(lyr) {
|
|
25698
25698
|
var features = exportLayerAsGeoJSON(lyr, dataset, opts, true, null);
|
|
25699
|
-
var
|
|
25700
|
-
|
|
25701
|
-
|
|
25699
|
+
var hasGeometry = features.some(function(feat) {
|
|
25700
|
+
return !!feat.geometry;
|
|
25701
|
+
});
|
|
25702
|
+
var output = buildGeoParquetColumns(features, hasGeometry);
|
|
25703
|
+
var writeOptions = {
|
|
25702
25704
|
columnData: output.columnData,
|
|
25703
|
-
|
|
25705
|
+
codec: compression.codec,
|
|
25706
|
+
compressors: compression.compressors,
|
|
25707
|
+
pageSize: compression.pageSize
|
|
25708
|
+
};
|
|
25709
|
+
if (hasGeometry) {
|
|
25710
|
+
writeOptions.kvMetadata = [{
|
|
25704
25711
|
key: 'geo',
|
|
25705
|
-
value: JSON.stringify(
|
|
25706
|
-
}]
|
|
25707
|
-
}
|
|
25708
|
-
|
|
25712
|
+
value: JSON.stringify(buildGeoMetadata(features, dataset))
|
|
25713
|
+
}];
|
|
25714
|
+
} else {
|
|
25715
|
+
warn('GeoParquet export: layer has no geometry; writing attribute data only.');
|
|
25716
|
+
}
|
|
25717
|
+
var content = writer.parquetWriteBuffer(writeOptions);
|
|
25718
|
+
files.push({
|
|
25709
25719
|
filename: filenameOverride || (lyr.name + '.' + extension),
|
|
25710
25720
|
content: content
|
|
25711
|
-
};
|
|
25721
|
+
});
|
|
25712
25722
|
});
|
|
25723
|
+
return files;
|
|
25713
25724
|
}
|
|
25714
25725
|
|
|
25715
|
-
function buildGeoParquetColumns(features,
|
|
25726
|
+
function buildGeoParquetColumns(features, includeGeometry) {
|
|
25716
25727
|
var geometryName = 'geometry';
|
|
25717
25728
|
var names = getPropertyNames(features);
|
|
25718
25729
|
var columnData = [];
|
|
25719
|
-
|
|
25720
|
-
|
|
25721
|
-
|
|
25722
|
-
|
|
25723
|
-
|
|
25724
|
-
|
|
25725
|
-
|
|
25730
|
+
if (features.length === 0) {
|
|
25731
|
+
stop$1('GeoParquet export requires at least one record');
|
|
25732
|
+
}
|
|
25733
|
+
if (includeGeometry) {
|
|
25734
|
+
columnData.push({
|
|
25735
|
+
name: geometryName,
|
|
25736
|
+
data: features.map(function(feat) {
|
|
25737
|
+
return feat.geometry || null;
|
|
25738
|
+
}),
|
|
25739
|
+
type: 'GEOMETRY'
|
|
25740
|
+
});
|
|
25741
|
+
}
|
|
25726
25742
|
names.forEach(function(name) {
|
|
25727
25743
|
var values = features.map(function(feat) {
|
|
25728
25744
|
return feat.properties ? feat.properties[name] : null;
|
|
25729
25745
|
});
|
|
25730
25746
|
columnData.push(buildAttributeColumn(name, values));
|
|
25731
25747
|
});
|
|
25748
|
+
if (columnData.length === 0) {
|
|
25749
|
+
stop$1('GeoParquet export requires geometry or attribute data');
|
|
25750
|
+
}
|
|
25732
25751
|
return {columnData: columnData, geometryColumn: geometryName};
|
|
25733
25752
|
}
|
|
25734
25753
|
|
|
@@ -25886,6 +25905,99 @@ ${svg}
|
|
|
25886
25905
|
return nodeMod.default && !nodeMod.parquetWriteBuffer ? nodeMod.default : nodeMod;
|
|
25887
25906
|
}
|
|
25888
25907
|
|
|
25908
|
+
async function getGeoParquetCompression(opts) {
|
|
25909
|
+
var codec = normalizeGeoParquetCompression(opts.compression);
|
|
25910
|
+
var level = validateGeoParquetCompressionLevel(opts.level, codec);
|
|
25911
|
+
if (codec != 'ZSTD') {
|
|
25912
|
+
return {codec: codec, compressors: null};
|
|
25913
|
+
}
|
|
25914
|
+
var zstd = await loadZstdLib();
|
|
25915
|
+
if (!zstd || typeof zstd.compress != 'function') {
|
|
25916
|
+
stop$1('GeoParquet ZSTD compressor is not loaded');
|
|
25917
|
+
}
|
|
25918
|
+
return {
|
|
25919
|
+
codec: codec,
|
|
25920
|
+
pageSize: getGeoParquetPageSize(level),
|
|
25921
|
+
compressors: {
|
|
25922
|
+
ZSTD: function(bytes) {
|
|
25923
|
+
return compressZstdPage(zstd, bytes, level);
|
|
25924
|
+
}
|
|
25925
|
+
}
|
|
25926
|
+
};
|
|
25927
|
+
}
|
|
25928
|
+
|
|
25929
|
+
function compressZstdPage(zstd, bytes, level) {
|
|
25930
|
+
var compressed;
|
|
25931
|
+
try {
|
|
25932
|
+
compressed = zstd.compress(bytes, level);
|
|
25933
|
+
} catch (e) {
|
|
25934
|
+
stop$1('Unable to apply GeoParquet ZSTD compression. Try a lower level= value.');
|
|
25935
|
+
}
|
|
25936
|
+
if (!compressed) {
|
|
25937
|
+
stop$1('Unable to apply GeoParquet ZSTD compression. Try a lower level= value.');
|
|
25938
|
+
}
|
|
25939
|
+
return compressed;
|
|
25940
|
+
}
|
|
25941
|
+
|
|
25942
|
+
function getGeoParquetPageSize(level) {
|
|
25943
|
+
return level >= 10 ? 64 * 1024 : undefined;
|
|
25944
|
+
}
|
|
25945
|
+
|
|
25946
|
+
function normalizeGeoParquetCompression(compression) {
|
|
25947
|
+
var str = compression === undefined || compression === null ? 'snappy' : String(compression).toLowerCase();
|
|
25948
|
+
if (str == 'snappy') return 'SNAPPY';
|
|
25949
|
+
if (str == 'zstd') return 'ZSTD';
|
|
25950
|
+
if (str == 'none' || str == 'uncompressed') return null;
|
|
25951
|
+
stop$1('Unsupported GeoParquet compression:', compression);
|
|
25952
|
+
}
|
|
25953
|
+
|
|
25954
|
+
function validateGeoParquetCompressionLevel(level, codec) {
|
|
25955
|
+
if (level === undefined) return undefined;
|
|
25956
|
+
if (codec != 'ZSTD') {
|
|
25957
|
+
stop$1('The level= option only applies with compression=zstd');
|
|
25958
|
+
}
|
|
25959
|
+
if (level >= 1 && level <= 22 && Math.floor(level) === level) {
|
|
25960
|
+
return level;
|
|
25961
|
+
}
|
|
25962
|
+
stop$1('GeoParquet ZSTD level= option must be an integer from 1 to 22');
|
|
25963
|
+
}
|
|
25964
|
+
|
|
25965
|
+
async function loadZstdLib() {
|
|
25966
|
+
var mod;
|
|
25967
|
+
if (runningInBrowser()) {
|
|
25968
|
+
mod = require$1('zstd-codec');
|
|
25969
|
+
} else {
|
|
25970
|
+
if (!zstdPromise) {
|
|
25971
|
+
zstdPromise = dynamicImportModule$1('zstd-codec');
|
|
25972
|
+
}
|
|
25973
|
+
mod = await zstdPromise;
|
|
25974
|
+
}
|
|
25975
|
+
if (mod && mod.default && !mod.ZstdCodec) {
|
|
25976
|
+
mod = mod.default;
|
|
25977
|
+
}
|
|
25978
|
+
if (!mod || !mod.ZstdCodec || typeof mod.ZstdCodec.run != 'function') {
|
|
25979
|
+
stop$1('GeoParquet ZSTD compressor is not loaded');
|
|
25980
|
+
}
|
|
25981
|
+
return initZstdCodec(mod.ZstdCodec);
|
|
25982
|
+
}
|
|
25983
|
+
|
|
25984
|
+
function initZstdCodec(codec) {
|
|
25985
|
+
return new Promise(function(resolve, reject) {
|
|
25986
|
+
try {
|
|
25987
|
+
codec.run(function(zstd) {
|
|
25988
|
+
var simple = new zstd.Simple();
|
|
25989
|
+
resolve({
|
|
25990
|
+
compress: function(bytes, level) {
|
|
25991
|
+
return simple.compress(bytes, level);
|
|
25992
|
+
}
|
|
25993
|
+
});
|
|
25994
|
+
});
|
|
25995
|
+
} catch (e) {
|
|
25996
|
+
reject(e);
|
|
25997
|
+
}
|
|
25998
|
+
});
|
|
25999
|
+
}
|
|
26000
|
+
|
|
25889
26001
|
function getOutputFormat(dataset, opts) {
|
|
25890
26002
|
var outFile = opts.file || null,
|
|
25891
26003
|
inFmt = dataset.info && dataset.info.input_formats && dataset.info.input_formats[0],
|
|
@@ -25991,6 +26103,9 @@ ${svg}
|
|
|
25991
26103
|
async function exportDatasets(datasets, opts) {
|
|
25992
26104
|
var format = getOutputFormat(datasets[0], opts);
|
|
25993
26105
|
var files;
|
|
26106
|
+
if (format != 'geoparquet' && (opts.compression || opts.level !== undefined)) {
|
|
26107
|
+
error('The compression= and level= options only apply to GeoParquet output');
|
|
26108
|
+
}
|
|
25994
26109
|
if (format == PACKAGE_EXT) {
|
|
25995
26110
|
opts = utils.defaults({compact: true}, opts);
|
|
25996
26111
|
return exportPackedDatasets(datasets, opts);
|
|
@@ -28669,6 +28784,13 @@ ${svg}
|
|
|
28669
28784
|
type: 'flag',
|
|
28670
28785
|
describe: '[CSV] export numbers with decimal commas not points'
|
|
28671
28786
|
})
|
|
28787
|
+
.option('compression', {
|
|
28788
|
+
describe: '[GeoParquet] options: snappy,zstd,none (default is snappy)'
|
|
28789
|
+
})
|
|
28790
|
+
.option('level', {
|
|
28791
|
+
describe: '[GeoParquet] zstd compression level',
|
|
28792
|
+
type: 'integer'
|
|
28793
|
+
})
|
|
28672
28794
|
.option('show-all', {
|
|
28673
28795
|
type: 'flag',
|
|
28674
28796
|
describe: '[Snapshot] show all layers in Web UI'
|
|
@@ -33675,6 +33797,7 @@ ${svg}
|
|
|
33675
33797
|
}
|
|
33676
33798
|
|
|
33677
33799
|
var hyparquetPromise = null;
|
|
33800
|
+
var compressorsPromise = null;
|
|
33678
33801
|
var dynamicImportModule = Function('id', 'return import(id)');
|
|
33679
33802
|
var mproj = null;
|
|
33680
33803
|
|
|
@@ -33685,8 +33808,10 @@ ${svg}
|
|
|
33685
33808
|
var file = await getHyparquetFile(source, hyparquet);
|
|
33686
33809
|
var metadata = await hyparquet.parquetMetadataAsync(file);
|
|
33687
33810
|
var geo = parseGeoParquetMetadata(metadata);
|
|
33811
|
+
var compressors = await loadHyparquetCompressors();
|
|
33688
33812
|
var rows = await hyparquet.parquetReadObjects({
|
|
33689
33813
|
file: file,
|
|
33814
|
+
compressors: compressors,
|
|
33690
33815
|
rowFormat: 'object'
|
|
33691
33816
|
});
|
|
33692
33817
|
var geometryColumn = getGeoParquetGeometryColumn(rows, geo);
|
|
@@ -33726,6 +33851,26 @@ ${svg}
|
|
|
33726
33851
|
return nodeMod.default && !nodeMod.parquetReadObjects ? nodeMod.default : nodeMod;
|
|
33727
33852
|
}
|
|
33728
33853
|
|
|
33854
|
+
async function loadHyparquetCompressors() {
|
|
33855
|
+
if (runningInBrowser()) {
|
|
33856
|
+
return getHyparquetCompressors(require$1('hyparquet-compressors'));
|
|
33857
|
+
}
|
|
33858
|
+
if (!compressorsPromise) {
|
|
33859
|
+
compressorsPromise = dynamicImportModule('hyparquet-compressors');
|
|
33860
|
+
}
|
|
33861
|
+
return getHyparquetCompressors(await compressorsPromise);
|
|
33862
|
+
}
|
|
33863
|
+
|
|
33864
|
+
function getHyparquetCompressors(mod) {
|
|
33865
|
+
if (mod && mod.default && !mod.compressors) {
|
|
33866
|
+
mod = mod.default;
|
|
33867
|
+
}
|
|
33868
|
+
if (!mod || !mod.compressors) {
|
|
33869
|
+
stop$1('GeoParquet compression library is not loaded');
|
|
33870
|
+
}
|
|
33871
|
+
return mod.compressors;
|
|
33872
|
+
}
|
|
33873
|
+
|
|
33729
33874
|
function getGeoParquetSource(input) {
|
|
33730
33875
|
if (!input) return null;
|
|
33731
33876
|
if (Object.prototype.hasOwnProperty.call(input, 'content')) {
|
|
@@ -54267,7 +54412,7 @@ ${svg}
|
|
|
54267
54412
|
});
|
|
54268
54413
|
}
|
|
54269
54414
|
|
|
54270
|
-
var version = "0.7.
|
|
54415
|
+
var version = "0.7.9";
|
|
54271
54416
|
|
|
54272
54417
|
// Parse command line args into commands and run them
|
|
54273
54418
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mapshaper",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.9",
|
|
4
4
|
"description": "A tool for editing vector datasets for mapping and GIS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shapefile",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"geographiclib-geodesic": "^2.2.0",
|
|
62
62
|
"geokdbush": "^1.1.0",
|
|
63
63
|
"hyparquet": "^1.25.6",
|
|
64
|
+
"hyparquet-compressors": "^1.1.1",
|
|
64
65
|
"hyparquet-writer": "^0.14.0",
|
|
65
66
|
"iconv-lite": "^0.6.3",
|
|
66
67
|
"idb-keyval": "^6.2.0",
|
|
@@ -69,7 +70,8 @@
|
|
|
69
70
|
"msgpackr": "^1.10.1",
|
|
70
71
|
"open": "^11.0.0",
|
|
71
72
|
"rw": "~1.3.3",
|
|
72
|
-
"tinyqueue": "^2.0.3"
|
|
73
|
+
"tinyqueue": "^2.0.3",
|
|
74
|
+
"zstd-codec": "^0.1.5"
|
|
73
75
|
},
|
|
74
76
|
"devDependencies": {
|
|
75
77
|
"@rollup/plugin-commonjs": "^28.0.6",
|
package/www/ai-config.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
var defaultProvider = "anthropic";
|
|
3
|
+
|
|
4
|
+
var common = {
|
|
5
|
+
enabled: true,
|
|
6
|
+
mode: "direct",
|
|
7
|
+
label: "Ask Mapshaper",
|
|
8
|
+
title: "Ask Mapshaper",
|
|
9
|
+
staticContextUrls: [
|
|
10
|
+
"/docs/ai/bot-instructions.html.md",
|
|
11
|
+
"/docs/ai/command-cheatsheet.html.md",
|
|
12
|
+
"/llms-full.txt"
|
|
13
|
+
],
|
|
14
|
+
sendRuntimeContext: true,
|
|
15
|
+
sendSampleValues: false,
|
|
16
|
+
allowRunCommands: false
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
var providers = {
|
|
20
|
+
anthropic: {
|
|
21
|
+
provider: "anthropic",
|
|
22
|
+
apiKey: "",
|
|
23
|
+
model: "claude-sonnet-4-6",
|
|
24
|
+
cacheControl: {type: "ephemeral"},
|
|
25
|
+
cacheTtl: "1h"
|
|
26
|
+
},
|
|
27
|
+
openai: {
|
|
28
|
+
provider: "openai",
|
|
29
|
+
apiKey: "",
|
|
30
|
+
model: "gpt-4.1-mini"
|
|
31
|
+
},
|
|
32
|
+
gemini: {
|
|
33
|
+
provider: "gemini",
|
|
34
|
+
apiKey: "",
|
|
35
|
+
model: "gemini-3.1-pro-preview"
|
|
36
|
+
},
|
|
37
|
+
mock: {
|
|
38
|
+
mode: "mock",
|
|
39
|
+
provider: "mock"
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
function getSelectedProvider() {
|
|
44
|
+
var params = new URLSearchParams(window.location.search);
|
|
45
|
+
return params.get("ai") || defaultProvider;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function mergeConfig() {
|
|
49
|
+
var selected = getSelectedProvider();
|
|
50
|
+
var providerConfig = providers[selected] || providers[defaultProvider];
|
|
51
|
+
return Object.assign({
|
|
52
|
+
selectedProvider: providers[selected] ? selected : defaultProvider
|
|
53
|
+
}, common, providerConfig);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
window.mapshaperAIConfigs = {
|
|
57
|
+
defaultProvider: defaultProvider,
|
|
58
|
+
common: common,
|
|
59
|
+
providers: providers
|
|
60
|
+
};
|
|
61
|
+
window.mapshaperAI = mergeConfig();
|
|
62
|
+
})();
|