@welldot/core 0.4.0-next.20261014.26249fd → 0.4.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 +14 -4
- package/dist/index.cjs +51 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +50 -2
- package/dist/index.js.map +1 -1
- package/examples/README.md +83 -0
- package/examples/belem-pa-condominio-outorga.well +961 -0
- package/examples/belem-pa-monitoramento-posto.well +1141 -0
- package/examples/belem-pa-pirabas-abastecimento.well +1751 -0
- package/examples/belem-pa-poco-colmatado.well +496 -0
- package/examples/belem-pa-poco-raso-abandonado.well +388 -0
- package/examples/belem-pa-qualidade-agua-acida.well +895 -0
- package/examples/colatina-es-gnaisse-rural.well +1047 -0
- package/examples/coluna-mg-cristalino-abastecimento.well +1437 -0
- package/examples/estrela-doeste-sp-bauru-serra-geral.well +919 -0
- package/examples/extremoz-rn-barreiras-raso.well +623 -0
- package/examples/gastao-vidigal-sp-dados-inconsistentes.well +222 -0
- package/examples/index.json +452 -0
- package/examples/irece-ba-carste-bambui.well +861 -0
- package/examples/lagoa-santa-mg-carste-abastecimento.well +1087 -0
- package/examples/minas-novas-mg-cadastro-incompleto.well +157 -0
- package/examples/quixeramobim-ce-cristalino-salobro.well +989 -0
- package/examples/rinopolis-sp-estratigrafico-guarani.well +287 -0
- package/examples/santarem-pa-jorrante-alter-do-chao.well +554 -0
- package/examples/sao-gabriel-rs-cacimba.well +360 -0
- package/examples/sete-lagoas-mg-carste-industrial.well +410 -0
- package/examples/thumbs/belem-pa-condominio-outorga.svg +1 -0
- package/examples/thumbs/belem-pa-monitoramento-posto.svg +1 -0
- package/examples/thumbs/belem-pa-pirabas-abastecimento.svg +1 -0
- package/examples/thumbs/belem-pa-poco-colmatado.svg +1 -0
- package/examples/thumbs/belem-pa-poco-raso-abandonado.svg +1 -0
- package/examples/thumbs/belem-pa-qualidade-agua-acida.svg +1 -0
- package/examples/thumbs/colatina-es-gnaisse-rural.svg +1 -0
- package/examples/thumbs/coluna-mg-cristalino-abastecimento.svg +1 -0
- package/examples/thumbs/estrela-doeste-sp-bauru-serra-geral.svg +1 -0
- package/examples/thumbs/extremoz-rn-barreiras-raso.svg +1 -0
- package/examples/thumbs/gastao-vidigal-sp-dados-inconsistentes.svg +1 -0
- package/examples/thumbs/irece-ba-carste-bambui.svg +1 -0
- package/examples/thumbs/lagoa-santa-mg-carste-abastecimento.svg +1 -0
- package/examples/thumbs/minas-novas-mg-cadastro-incompleto.svg +1 -0
- package/examples/thumbs/quixeramobim-ce-cristalino-salobro.svg +1 -0
- package/examples/thumbs/rinopolis-sp-estratigrafico-guarani.svg +1 -0
- package/examples/thumbs/santarem-pa-jorrante-alter-do-chao.svg +1 -0
- package/examples/thumbs/sao-gabriel-rs-cacimba.svg +1 -0
- package/examples/thumbs/sete-lagoas-mg-carste-industrial.svg +1 -0
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -26,6 +26,10 @@ The format is designed for three use cases: visualization of technical well prof
|
|
|
26
26
|
|
|
27
27
|
See the [v2 format specification](./docs/spec/v2/overview.md) (current revision: v2.3) for the complete schema reference and design rationale. The [v1 spec](./docs/spec/v1/well-format.md) remains available for reference.
|
|
28
28
|
|
|
29
|
+
### Example wells
|
|
30
|
+
|
|
31
|
+
The package ships 14 complete, valid `.well` files in [`examples/`](./examples/README.md). They are built on real wells from the Brazilian SIAGAS registry, with illustrative names, permits, analyses and operating data. Together they cover crystalline, karst, sedimentary, deep, flowing, hand-dug and monitoring wells, plus incomplete and inconsistent records. Import them as `@welldot/core/examples/<file>`, or download them from `https://welldot.org/examples/<file>`.
|
|
32
|
+
|
|
29
33
|
## Installation
|
|
30
34
|
|
|
31
35
|
```bash
|
|
@@ -50,6 +54,7 @@ import {
|
|
|
50
54
|
parseWell,
|
|
51
55
|
serializeWell,
|
|
52
56
|
deserializeWell,
|
|
57
|
+
hasWellData,
|
|
53
58
|
isWellEmpty,
|
|
54
59
|
} from '@welldot/core';
|
|
55
60
|
|
|
@@ -65,8 +70,9 @@ const jsonString = serializeWell(well);
|
|
|
65
70
|
// Deserialize — handles versioned format and legacy formats
|
|
66
71
|
const restored = deserializeWell(jsonString);
|
|
67
72
|
|
|
68
|
-
// Check if a well
|
|
73
|
+
// Check if a well has a profile to draw, or holds any data at all
|
|
69
74
|
const empty = isWellEmpty(well);
|
|
75
|
+
const hasData = hasWellData(well);
|
|
70
76
|
```
|
|
71
77
|
|
|
72
78
|
## API Reference
|
|
@@ -219,11 +225,11 @@ Each schema validates its corresponding type at runtime. All schemas are Zod obj
|
|
|
219
225
|
|
|
220
226
|
#### `parseWell(json: string): Well`
|
|
221
227
|
|
|
222
|
-
Parses a raw JSON string and validates it against `WellSchema`. Throws a `ZodError` on validation failure. Does not handle legacy formats — use `deserializeWell` for that.
|
|
228
|
+
Parses a raw JSON string and validates it against `WellSchema`. Throws a `ZodError` on validation failure. Unknown members (`x-` fields and blocks) are kept at every level, including inside array items. Does not handle legacy formats — use `deserializeWell` for that.
|
|
223
229
|
|
|
224
230
|
#### `serializeWell(well: Well): string`
|
|
225
231
|
|
|
226
|
-
Serializes a `Well` object to a versioned `.well` JSON string (`"version": 2`). Emits `location` when set; does not emit deprecated flat `lat`/`lng`/`elevation
|
|
232
|
+
Serializes a `Well` object to a versioned `.well` JSON string (`"version": 2`). Emits `location` when set; does not emit deprecated flat `lat`/`lng`/`elevation` or other legacy v1 keys. Omits `undefined` optional fields. Root members the spec does not define (`x-` fields and blocks, foreign members) are written unchanged after the spec blocks, as the spec requires.
|
|
227
233
|
|
|
228
234
|
#### `deserializeWell(jsonString: string): Well | null`
|
|
229
235
|
|
|
@@ -241,13 +247,17 @@ Returns `null` if the parsed data is empty. Throws on unrecognized version numbe
|
|
|
241
247
|
|
|
242
248
|
Returns `true` when all constructive and geologic arrays are empty. Accepts `null` and `undefined` (both treated as empty).
|
|
243
249
|
|
|
250
|
+
#### `hasWellData(well: Well | null | undefined): boolean`
|
|
251
|
+
|
|
252
|
+
Returns `true` when the well holds any data: a profile, or any other filled root member (identification, location, events, samples, permits, `x-` members, …). A registry record without construction or geology has data although `isWellEmpty` says it has nothing to draw. Blank strings, zeros and objects holding only those do not count.
|
|
253
|
+
|
|
244
254
|
#### `calculatedWellDepth(well: Well): number`
|
|
245
255
|
|
|
246
256
|
Deepest `to` across the constructive arrays (bore hole, casings, screens, reductions, hole fill), ignoring geology. `0` without constructive data. Used as the fallback for a missing `well_depth`.
|
|
247
257
|
|
|
248
258
|
#### `redactWell(well: Well, visibility: WellVisibility): Well`
|
|
249
259
|
|
|
250
|
-
Copy of `well` with hidden parts emptied (arrays become `[]`, optional fields are removed), so the result stays schema-valid. `visibility` keys are the 7 `SECTION_KEYS` and/or the fields of `VISIBILITY_TREE` (e.g. `meters`, `permits`, `location`); `false` hides, missing keys are visible, and a hidden section hides all its fields. `VISIBILITY_LEAF_KEYS` lists the finest toggles. References from visible records to hidden ones are left as-is.
|
|
260
|
+
Copy of `well` with hidden parts emptied (arrays become `[]`, optional fields are removed), so the result stays schema-valid. `visibility` keys are the 7 `SECTION_KEYS` and/or the fields of `VISIBILITY_TREE` (e.g. `meters`, `permits`, `location`); `false` hides, missing keys are visible, and a hidden section hides all its fields. `VISIBILITY_LEAF_KEYS` lists the finest toggles. References from visible records to hidden ones are left as-is. Unknown root members (`x-` fields and blocks) are kept only when nothing is hidden; nested ones follow their record.
|
|
251
261
|
|
|
252
262
|
```typescript
|
|
253
263
|
redactWell(well, { operation: false }); // whole section
|
package/dist/index.cjs
CHANGED
|
@@ -161,6 +161,7 @@ __export(index_exports, {
|
|
|
161
161
|
getParameterLabel: () => getParameterLabel,
|
|
162
162
|
getVocabEntry: () => getVocabEntry,
|
|
163
163
|
getVocabLabel: () => getVocabLabel,
|
|
164
|
+
hasWellData: () => hasWellData,
|
|
164
165
|
hoursToMinutes: () => hoursToMinutes,
|
|
165
166
|
hpToKilowatts: () => hpToKilowatts,
|
|
166
167
|
inchesToMm: () => inchesToMm,
|
|
@@ -209,6 +210,16 @@ var mergeWell = (0, import_defu.createDefu)((obj, key, value) => {
|
|
|
209
210
|
return true;
|
|
210
211
|
}
|
|
211
212
|
});
|
|
213
|
+
var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
214
|
+
var mergeParsed = (0, import_defu.createDefu)((obj, key, value) => {
|
|
215
|
+
if (Array.isArray(value)) {
|
|
216
|
+
const raw = obj[key];
|
|
217
|
+
obj[key] = Array.isArray(raw) && raw.length === value.length ? value.map(
|
|
218
|
+
(item, i) => isPlainObject(item) && isPlainObject(raw[i]) ? mergeParsed(item, raw[i]) : item
|
|
219
|
+
) : value;
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
});
|
|
212
223
|
var RFC3339_WITH_OFFSET = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
|
|
213
224
|
var rfc3339 = () => import_zod.z.string().regex(RFC3339_WITH_OFFSET, "datetime must be RFC 3339 with UTC offset");
|
|
214
225
|
var CALENDAR_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
@@ -840,7 +851,7 @@ function parseWell(json) {
|
|
|
840
851
|
}
|
|
841
852
|
if (version === 1) {
|
|
842
853
|
const normalized = normalizeV1Fields(raw);
|
|
843
|
-
return
|
|
854
|
+
return mergeParsed(
|
|
844
855
|
WellSchema.parse(normalized),
|
|
845
856
|
normalized
|
|
846
857
|
);
|
|
@@ -850,12 +861,20 @@ function parseWell(json) {
|
|
|
850
861
|
} else {
|
|
851
862
|
raw.version = 2;
|
|
852
863
|
}
|
|
853
|
-
return
|
|
864
|
+
return mergeParsed(WellSchema.parse(raw), raw);
|
|
854
865
|
}
|
|
855
866
|
|
|
856
867
|
// src/utils/well.utils.ts
|
|
857
868
|
var WELL_FORMAT_VERSION = 2;
|
|
858
869
|
var INCHES_TO_MM = 25.4;
|
|
870
|
+
var LEGACY_ROOT_KEYS = /* @__PURE__ */ new Set([
|
|
871
|
+
"lat",
|
|
872
|
+
"lng",
|
|
873
|
+
"elevation",
|
|
874
|
+
"bole_hole",
|
|
875
|
+
"constructive",
|
|
876
|
+
"geologic"
|
|
877
|
+
]);
|
|
859
878
|
var SECTION_KEYS = [
|
|
860
879
|
"general",
|
|
861
880
|
"constructive",
|
|
@@ -1100,6 +1119,11 @@ function normalizeGeologic(raw) {
|
|
|
1100
1119
|
caves: raw.caves ?? []
|
|
1101
1120
|
};
|
|
1102
1121
|
}
|
|
1122
|
+
function unknownRootKeys(well) {
|
|
1123
|
+
return Object.keys(well).filter(
|
|
1124
|
+
(key) => !(key in WellSchema.shape) && !LEGACY_ROOT_KEYS.has(key)
|
|
1125
|
+
);
|
|
1126
|
+
}
|
|
1103
1127
|
function serializeWell(well) {
|
|
1104
1128
|
const payload = {
|
|
1105
1129
|
version: WELL_FORMAT_VERSION,
|
|
@@ -1152,6 +1176,10 @@ function serializeWell(well) {
|
|
|
1152
1176
|
water_samples: well.water_samples
|
|
1153
1177
|
}
|
|
1154
1178
|
};
|
|
1179
|
+
for (const key of unknownRootKeys(well)) {
|
|
1180
|
+
const value = well[key];
|
|
1181
|
+
if (value !== void 0) payload[key] = value;
|
|
1182
|
+
}
|
|
1155
1183
|
return JSON.stringify(payload);
|
|
1156
1184
|
}
|
|
1157
1185
|
function isWellEmpty(well) {
|
|
@@ -1160,6 +1188,22 @@ function isWellEmpty(well) {
|
|
|
1160
1188
|
if (raw.constructive || raw.geologic) return false;
|
|
1161
1189
|
return well.lithology?.length === 0 && well.fractures?.length === 0 && well.caves?.length === 0 && well.bore_hole?.length === 0 && well.hole_fill?.length === 0 && well.well_case?.length === 0 && well.well_screen?.length === 0;
|
|
1162
1190
|
}
|
|
1191
|
+
function isFilled(value) {
|
|
1192
|
+
if (value === void 0 || value === null) return false;
|
|
1193
|
+
if (typeof value === "string") return value.trim() !== "";
|
|
1194
|
+
if (typeof value === "number") return value !== 0;
|
|
1195
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
1196
|
+
if (typeof value === "object") return Object.values(value).some(isFilled);
|
|
1197
|
+
return true;
|
|
1198
|
+
}
|
|
1199
|
+
var NON_DATA_ROOT_KEYS = /* @__PURE__ */ new Set(["version", "$schema", "@context"]);
|
|
1200
|
+
function hasWellData(well) {
|
|
1201
|
+
if (!well) return false;
|
|
1202
|
+
if (!isWellEmpty(well)) return true;
|
|
1203
|
+
return Object.entries(well).some(
|
|
1204
|
+
([key, value]) => !NON_DATA_ROOT_KEYS.has(key) && isFilled(value)
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1163
1207
|
function redactWell(well, visibility) {
|
|
1164
1208
|
const v = visibility;
|
|
1165
1209
|
const redacted = { ...well };
|
|
@@ -1203,6 +1247,10 @@ function redactWell(well, visibility) {
|
|
|
1203
1247
|
if (hidden("production")) delete redacted.production;
|
|
1204
1248
|
if (hidden("permits")) delete redacted.permits;
|
|
1205
1249
|
if (hidden("water_quality")) delete redacted.water_samples;
|
|
1250
|
+
if (Object.values(v).some((shown) => shown === false)) {
|
|
1251
|
+
for (const key of unknownRootKeys(redacted))
|
|
1252
|
+
delete redacted[key];
|
|
1253
|
+
}
|
|
1206
1254
|
return redacted;
|
|
1207
1255
|
}
|
|
1208
1256
|
function deserializeWell(jsonString) {
|
|
@@ -3393,6 +3441,7 @@ function expandedToStandardUncertainty(expanded, coverageFactor = 2) {
|
|
|
3393
3441
|
getParameterLabel,
|
|
3394
3442
|
getVocabEntry,
|
|
3395
3443
|
getVocabLabel,
|
|
3444
|
+
hasWellData,
|
|
3396
3445
|
hoursToMinutes,
|
|
3397
3446
|
hpToKilowatts,
|
|
3398
3447
|
inchesToMm,
|