{"_id":"@cristianob/metar-parser","_rev":"5-7d596443c1f37d34fc3df0ed5d408820","name":"@cristianob/metar-parser","dist-tags":{"latest":"1.3.0"},"versions":{"1.0.0":{"name":"@cristianob/metar-parser","version":"1.0.0","_id":"@cristianob/metar-parser@1.0.0","maintainers":[{"name":"cristianobcosta","email":"cristiano@cristianocosta.me"}],"dist":{"shasum":"0ae7c4d05f137a3ea7079485150470ac7cacec58","tarball":"https://registry.npmjs.org/@cristianob/metar-parser/-/metar-parser-1.0.0.tgz","fileCount":5,"integrity":"sha512-V8Z2Bx7QvWYrTaw5JezrW9+h7QtsDUZJjCNBniEt+5OaYlo33skSPnJtBtndVGPHnLMDh9JGHjOOwIdhujcaNA==","signatures":[{"sig":"MEQCID/7ae3sP3qQnPFVRkvjC6u05pB82pxcjyMxmbTGM9RpAiAimGtE7lDYWeCbOc87uC9WZm+N8ZF44h+jNmVDhyG/9A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82213},"main":"./dist/metar-parser.js","type":"module","types":"./dist/metar-parser.d.ts","exports":{".":{"types":"./dist/metar-parser.d.ts","import":"./dist/metar-parser.js","default":"./dist/metar-parser.js"}},"gitHead":"537d995fbbe417ab4a12db99e50f7505533de869","scripts":{"test":"vitest run --globals","build":"tsup"},"_npmUser":{"name":"cristianobcosta","email":"cristiano@cristianocosta.me"},"_npmVersion":"11.6.2","description":"METAR parser with structured output for international reports","directories":{},"sideEffects":false,"_nodeVersion":"24.13.0","react-native":"./dist/metar-parser.js","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.2","typescript":"^6.0.2","@types/node":"^25.5.0","@rolldown/binding-linux-x64-gnu":"1.0.0-rc.12"},"_npmOperationalInternal":{"tmp":"tmp/metar-parser_1.0.0_1774637185896_0.3611863717874968","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@cristianob/metar-parser","version":"1.1.0","_id":"@cristianob/metar-parser@1.1.0","maintainers":[{"name":"cristianobcosta","email":"cristiano@cristianocosta.me"}],"dist":{"shasum":"a9c3fe2fddcceb1bb37da671ff483837d12ce99b","tarball":"https://registry.npmjs.org/@cristianob/metar-parser/-/metar-parser-1.1.0.tgz","fileCount":5,"integrity":"sha512-x38h7rGj+QR4KYIUH3HvBn1WZT4vS6swvvJ1R4WgMPUhMJPNcusjBQy12cwmbj6nl0SrSfnpKxize4P9lHgOiA==","signatures":[{"sig":"MEQCIFIVBfy9wMuLO6YLFAovUxg9coZE8uBu9mjltfqdgkyKAiA2Te0CV5F4YIzCx1QkyQ16CxQgbUFJMwm1GeM4rNwokw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82221},"main":"./dist/metar-parser.js","type":"module","types":"./dist/metar-parser.d.ts","exports":{".":{"types":"./dist/metar-parser.d.ts","import":"./dist/metar-parser.js","default":"./dist/metar-parser.js"}},"gitHead":"6380dd4cf5a13c3cf71a2c0e95add1e66a98ec1d","scripts":{"test":"vitest run --globals","build":"tsup"},"_npmUser":{"name":"cristianobcosta","email":"cristiano@cristianocosta.me"},"_npmVersion":"11.6.2","description":"METAR parser with structured output for international reports","directories":{},"sideEffects":false,"_nodeVersion":"24.13.0","react-native":"./dist/metar-parser.js","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.2","typescript":"^6.0.2","@types/node":"^25.5.0","@rolldown/binding-linux-x64-gnu":"1.0.0-rc.12"},"_npmOperationalInternal":{"tmp":"tmp/metar-parser_1.1.0_1776798254848_0.6443598290436243","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@cristianob/metar-parser","version":"1.2.0","_id":"@cristianob/metar-parser@1.2.0","maintainers":[{"name":"cristianobcosta","email":"cristiano@cristianocosta.me"}],"dist":{"shasum":"4a5d6c0b4251530a37a615b713a48137e49ff4e4","tarball":"https://registry.npmjs.org/@cristianob/metar-parser/-/metar-parser-1.2.0.tgz","fileCount":5,"integrity":"sha512-tcUxaPgMpIjWXi5yZk9Kd8tMF98gFi1ZlaCMah10beD76gGYEtrjQga2T+5GZbF66Be1btQrbbezzWiMo/TBeg==","signatures":[{"sig":"MEUCIQC5zFAtLTQRKPgxVci8fr3jkqbhB4aac4dT/+Dr2E6BewIgR+F3elaZLMYEbl5+pQWhB7w0eqdqfSNY5ot8wfHnlrY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82221},"main":"./dist/metar-parser.js","type":"module","types":"./dist/metar-parser.d.ts","exports":{".":{"types":"./dist/metar-parser.d.ts","import":"./dist/metar-parser.js","default":"./dist/metar-parser.js"}},"gitHead":"966ecc333fea1040e621a674ab04fabad320823e","scripts":{"test":"vitest run --globals","build":"tsup"},"_npmUser":{"name":"cristianobcosta","email":"cristiano@cristianocosta.me"},"_npmVersion":"11.6.2","description":"METAR parser with structured output for international reports","directories":{},"sideEffects":false,"_nodeVersion":"24.13.0","react-native":"./dist/metar-parser.js","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.2","typescript":"^6.0.2","@types/node":"^25.5.0","@rolldown/binding-linux-x64-gnu":"1.0.0-rc.12"},"_npmOperationalInternal":{"tmp":"tmp/metar-parser_1.2.0_1777301541374_0.9414500932486791","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"@cristianob/metar-parser","version":"1.2.1","_id":"@cristianob/metar-parser@1.2.1","maintainers":[{"name":"cristianobcosta","email":"cristiano@cristianocosta.me"}],"dist":{"shasum":"c1471c22135331a7b165910aa5f29ae61f2c258f","tarball":"https://registry.npmjs.org/@cristianob/metar-parser/-/metar-parser-1.2.1.tgz","fileCount":5,"integrity":"sha512-pvhnvUdT2I54A5cwCV8M3UZdH7Y5JgOGX2KAI1OGQLM4N7rjoSsAkNkK1PR49bok0g7IcObXsF4aVBS3sm/VGQ==","signatures":[{"sig":"MEUCIFPFy6RvlB3uX7maloF0CNqqDh7maFw/YHcA35w9mVmlAiEA4NeuFsaURWQVKqoQyaiJseh9DqsOmyJBf/CUyjaEbEs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":84069},"main":"./dist/metar-parser.js","type":"module","types":"./dist/metar-parser.d.ts","exports":{".":{"types":"./dist/metar-parser.d.ts","import":"./dist/metar-parser.js","default":"./dist/metar-parser.js"}},"gitHead":"295156e4be3e468e95190bbcea7d764571485f1b","scripts":{"test":"vitest run --globals","build":"tsup"},"_npmUser":{"name":"cristianobcosta","email":"cristiano@cristianocosta.me"},"_npmVersion":"11.6.2","description":"METAR parser with structured output for international reports","directories":{},"sideEffects":false,"_nodeVersion":"24.13.0","react-native":"./dist/metar-parser.js","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.2","typescript":"^6.0.2","@types/node":"^25.5.0","@rolldown/binding-linux-x64-gnu":"1.0.0-rc.12"},"_npmOperationalInternal":{"tmp":"tmp/metar-parser_1.2.1_1777301725564_0.4816284575012977","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@cristianob/metar-parser","version":"1.3.0","description":"METAR parser with structured output for international reports","main":"./dist/metar-parser.js","react-native":"./dist/metar-parser.js","types":"./dist/metar-parser.d.ts","type":"module","sideEffects":false,"exports":{".":{"types":"./dist/metar-parser.d.ts","import":"./dist/metar-parser.js","default":"./dist/metar-parser.js"}},"scripts":{"build":"tsup","test":"vitest run --globals"},"devDependencies":{"@rolldown/binding-linux-x64-gnu":"1.0.0-rc.12","@types/node":"^25.5.0","tsup":"^8.5.1","typescript":"^6.0.2","vitest":"^4.1.2"},"gitHead":"34b40124be39918de65e04039590301ff71c57d3","_id":"@cristianob/metar-parser@1.3.0","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-ClI4rYULa3OGpLR0Y4RuutjekAtE+ZfAMULmpsfd462oyx88CA4ZzL/HUEnK/Z9aX9vGj+aXtv8QEuqt/C6JCw==","shasum":"68d03ed3c92b8ab7d2b6d1a5d44a105f9876cf7e","tarball":"https://registry.npmjs.org/@cristianob/metar-parser/-/metar-parser-1.3.0.tgz","fileCount":5,"unpackedSize":84097,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCDTEp7vlFy0a+Bp22g+thS/3ugzlFFP3Q3+PJTQ+ByNAIhAJz18tqT3Q14kbeC4iaKLwt0JsEcXFtdopSJYfLUAaxZ"}]},"_npmUser":{"name":"cristianobcosta","email":"cristiano@cristianocosta.me"},"directories":{},"maintainers":[{"name":"cristianobcosta","email":"cristiano@cristianocosta.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/metar-parser_1.3.0_1777314912679_0.6914425604045855"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-27T18:46:25.728Z","modified":"2026-04-27T18:35:13.005Z","1.0.0":"2026-03-27T18:46:26.043Z","1.1.0":"2026-04-21T19:04:14.987Z","1.2.0":"2026-04-27T14:52:21.515Z","1.2.1":"2026-04-27T14:55:25.751Z","1.3.0":"2026-04-27T18:35:12.878Z"},"description":"METAR parser with structured output for international reports","maintainers":[{"name":"cristianobcosta","email":"cristiano@cristianocosta.me"}],"readme":"# Metar Parser\n\nParser de METAR em TypeScript com saída estruturada, sem dependências de runtime e pronto para:\n\n- aplicações web com bundlers\n- React na web\n- React Native\n- HTML puro via bundle global\n\nO objetivo da biblioteca é transformar o METAR bruto em um objeto consistente, semântico e fácil de consumir em interfaces, regras de negócio, automações e agentes de AI.\n\n## Instalação\n\n```bash\npnpm add @cristianob/metar-parser\n```\n\n## Uso rápido\n\n### ESM / TypeScript\n\n```ts\nimport parseMETAR, { type MetarParseResult } from \"@cristianob/metar-parser\";\n\nconst result: MetarParseResult = parseMETAR(\n  \"METAR SBGR 261200Z 35008KT 9999 SCT040 28/18 Q1012\"\n);\n\nconsole.log(result.station); // \"SBGR\"\nconsole.log(result.wind.speed); // 8\nconsole.log(result.altimeter.hPa); // 1012\n```\n\n### React / React Native\n\n```ts\nimport parseMETAR from \"@cristianob/metar-parser\";\n\nexport function parseReport(message: string) {\n  return parseMETAR(message);\n}\n```\n\n### HTML puro\n\nDepois do build, use o bundle global:\n\n```html\n<script src=\"./dist/metar-parser.global.js\"></script>\n<script>\n  const result = window.parseMETAR(\n    \"METAR SBGL 261300Z 18010KT CAVOK 30/20 Q1015\"\n  );\n\n  console.log(result);\n</script>\n```\n\nO bundle global expõe:\n\n- `window.parseMETAR`\n\n## O que a biblioteca parseia\n\n- `METAR` e `SPECI`\n- estação ICAO\n- data/hora do relatório\n- `AUTO`\n- correções `COR` e variações `CCx`\n- vento, rajada, operadores `P`, direção variável e faixa `dddVddd`\n- `CAVOK`\n- visibilidade em metros e em `SM`, incluindo:\n  - `9999`\n  - `////`\n  - `10SM`\n  - `P6SM`\n  - `M1/4SM`\n  - `1 1/2SM`\n  - visibilidade mínima direcional como `2000SW`\n- `RVR` com quantidade ilimitada\n- estado de pista suplementar\n- weather por grupo semântico\n- nuvens, `CB`, `TCU`, bases indisponíveis e `//////CB`\n- visibilidade vertical `VV`\n- temperatura e dew point, inclusive negativos\n- altímetro `Q` e `A`, sempre com `hPa` e `inHg`\n- tempo recente `RE...`\n- wind shear\n- sea state\n- tendências `NOSIG`, `BECMG`, `TEMPO`, com `FM`, `TL` e `AT`\n- `RMK` parcial com suporte semântico atual para:\n  - `AUT`\n  - `QFE###`\n  - `QFE####`\n\n## Comportamento do parser\n\n- O núcleo do METAR é validado. Estação, hora, vento e visibilidade obrigatória inválidos geram erro.\n- A parte suplementar é permissiva. Tokens desconhecidos são ignorados.\n- `RMK` é preservado mesmo quando não é totalmente interpretado.\n- `weather` é semântico por grupo, não uma lista achatada de abreviações.\n- `VV` fica em `visibility.vertical`, não em `clouds`.\n- O altímetro sempre expõe:\n  - valor na unidade original\n  - conversão para `inHg`\n  - conversão para `hPa`\n\n## Limitações atuais\n\n- `RMK` americano ainda não é decodificado por completo.\n- A propriedade `time` é um `Date` construído com:\n  - dia/hora/minuto do METAR\n  - mês e ano atuais do ambiente em UTC\n\nIsso funciona bem para consumo operacional corrente, mas não reconstrói contexto histórico completo sem informação externa.\n\n## API\n\n### `parseMETAR(message: string): MetarParseResult`\n\nRecebe um METAR bruto e retorna um objeto estruturado.\n\n```ts\nimport parseMETAR from \"@cristianob/metar-parser\";\n\nconst result = parseMETAR(\n  \"METAR SBMN 261200Z 04008KT 9999 SCT025 BKN100 30/24 Q1012 RERA WS ALL RWY RMK AUT QFE750\"\n);\n```\n\n### Erros\n\nQuando o parser falha no núcleo obrigatório do relatório, ele lança `Error` com metadados adicionais:\n\n- `tokenIndex?: number`\n- `token?: string | null`\n\n```ts\ntry {\n  parseMETAR(\"METAR INVALID\");\n} catch (error) {\n  const err = error as Error & { tokenIndex?: number; token?: string | null };\n\n  console.error(err.message);\n  console.error(err.tokenIndex);\n  console.error(err.token);\n}\n```\n\n## Exemplo completo\n\nEntrada:\n\n```txt\nMETAR SBMN 261200Z 04008KT 9999 SCT025 BKN100 30/24 Q1012 RERA WS ALL RWY RMK AUT QFE750\n```\n\nSaída resumida:\n\n```json\n{\n  \"original\": \"METAR SBMN 261200Z 04008KT 9999 SCT025 BKN100 30/24 Q1012 RERA WS ALL RWY RMK AUT QFE750\",\n  \"type\": \"METAR\",\n  \"station\": \"SBMN\",\n  \"time\": \"Date(...)\",\n  \"auto\": false,\n  \"correction\": false,\n  \"wind\": {\n    \"raw\": \"04008KT\",\n    \"speed\": 8,\n    \"gust\": null,\n    \"direction\": 40,\n    \"variation\": null,\n    \"unit\": \"KT\",\n    \"speedOperator\": null,\n    \"gustOperator\": null,\n    \"calm\": false\n  },\n  \"visibility\": {\n    \"prevailing\": {\n      \"raw\": \"9999\",\n      \"value\": 9999,\n      \"unit\": \"m\",\n      \"greaterThan\": false,\n      \"lessThan\": false,\n      \"unavailable\": false\n    },\n    \"minimum\": null,\n    \"vertical\": null\n  },\n  \"clouds\": [\n    {\n      \"raw\": \"SCT025\",\n      \"abbreviation\": \"SCT\",\n      \"meaning\": \"scattered\",\n      \"altitude\": 2500,\n      \"cumulonimbus\": false,\n      \"toweringCumulus\": false,\n      \"type\": \"layer\",\n      \"baseUnavailable\": false,\n      \"convectiveType\": null\n    },\n    {\n      \"raw\": \"BKN100\",\n      \"abbreviation\": \"BKN\",\n      \"meaning\": \"broken\",\n      \"altitude\": 10000,\n      \"cumulonimbus\": false,\n      \"toweringCumulus\": false,\n      \"type\": \"layer\",\n      \"baseUnavailable\": false,\n      \"convectiveType\": null\n    }\n  ],\n  \"temperature\": {\n    \"raw\": \"30/24\",\n    \"air\": 30,\n    \"dewpoint\": 24\n  },\n  \"altimeter\": {\n    \"raw\": \"Q1012\",\n    \"value\": 1012,\n    \"unit\": \"hPa\",\n    \"inHg\": 29.88,\n    \"hPa\": 1012\n  },\n  \"recentWeather\": [\n    {\n      \"raw\": \"RERA\",\n      \"code\": \"RERA\",\n      \"description\": \"moderate or heavy rain\"\n    }\n  ],\n  \"windShear\": [\n    {\n      \"raw\": \"WS ALL RWY\",\n      \"allRunways\": true,\n      \"runway\": null\n    }\n  ],\n  \"remarks\": {\n    \"raw\": \"AUT QFE750\",\n    \"tokens\": [\"AUT\", \"QFE750\"],\n    \"automatic\": true,\n    \"qfe\": {\n      \"raw\": \"QFE750\",\n      \"value\": 750,\n      \"unit\": \"mmHg\",\n      \"description\": \"field elevation pressure\"\n    },\n    \"unparsedTokens\": []\n  }\n}\n```\n\n## Tipos de saída\n\nAs tabelas abaixo descrevem o contrato público da saída.\n\nConvenções:\n\n- `T | null` significa que a propriedade pode existir sem valor\n- `[]` representa itens de array\n- quando um campo só existe em um subtipo, isso é indicado na descrição\n\n## Resultado principal\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `original` | `string` | METAR normalizado, com espaços colapsados. | `\"METAR SBGR 261200Z 35008KT 9999 SCT040 28/18 Q1012\"` |\n| `type` | `\"METAR\" \\| \"SPECI\"` | Tipo do relatório. | `\"METAR\"` |\n| `station` | `string \\| null` | Código ICAO de 4 letras. | `\"SBGR\"` |\n| `time` | `Date \\| null` | Data UTC montada a partir de dia/hora/minuto do METAR e mês/ano atuais do ambiente. | `new Date(\"2026-03-26T12:00:00.000Z\")` |\n| `auto` | `boolean` | Indica presença de `AUTO`. | `true` |\n| `correction` | `boolean \\| string` | `true` para `COR` ou `CC`; string quando vier `CCA`, `CCB` etc. | `true`, `\"A\"` |\n| `cavok` | `boolean` | Indica presença de `CAVOK`. | `true` |\n| `wind` | `WindGroup` | Bloco de vento. | `{ raw: \"35008KT\", ... }` |\n| `visibility` | `VisibilityBlock` | Bloco de visibilidade. | `{ prevailing: {...}, minimum: null, vertical: null }` |\n| `rvr` | `RvrGroup[] \\| null` | Lista de RVR. | `[{ raw: \"R27L/0800N\", ... }]` |\n| `runwayState` | `RunwayStateGroup[] \\| null` | Estado de pista suplementar. | `[{ raw: \"R25/190063\", ... }]` |\n| `weather` | `WeatherGroup[] \\| null` | Weather do corpo principal. | `[{ raw: \"-TSRA\", ... }]` |\n| `trend` | `TrendGroup[] \\| null` | Tendências do relatório. | `[{ raw: \"NOSIG\", ... }]` |\n| `clouds` | `CloudGroup[] \\| null` | Nuvens do corpo principal. | `[{ raw: \"BKN040CB\", ... }]` |\n| `temperature` | `TemperatureGroup` | Temperatura e dew point. | `{ raw: \"28/18\", air: 28, dewpoint: 18 }` |\n| `altimeter` | `AltimeterGroup` | Altímetro com unidade original e conversões. | `{ raw: \"Q1012\", value: 1012, unit: \"hPa\", inHg: 29.88, hPa: 1012 }` |\n| `recentWeather` | `RecentWeatherGroup[] \\| null` | Tempo recente `RE...`. | `[{ raw: \"RERA\", code: \"RERA\", description: \"moderate or heavy rain\" }]` |\n| `windShear` | `WindShearGroup[] \\| null` | Wind shear suplementar. | `[{ raw: \"WS ALL RWY\", allRunways: true, runway: null }]` |\n| `seaState` | `SeaStateGroup \\| null` | Estado do mar. | `{ raw: \"W18/S4\", seaSurfaceTemperatureC: 18, seaConditionCode: 4, waveHeightDm: null }` |\n| `remarks` | `RemarksGroup \\| null` | Grupo `RMK` preservado e parcialmente enriquecido. | `{ raw: \"AUT QFE750\", ... }` |\n\n## Vento\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `wind.raw` | `string \\| null` | Grupo bruto de vento. | `\"35008G22KT\"` |\n| `wind.speed` | `number \\| null` | Velocidade média. | `8` |\n| `wind.gust` | `number \\| null` | Rajada. | `22` |\n| `wind.direction` | `number \\| \"VRB\" \\| null` | Direção do vento ou `VRB`. | `350`, `\"VRB\"` |\n| `wind.variation` | `true \\| { min: number; max: number } \\| null` | `true` para direção variável pura ou faixa `dddVddd`. | `true`, `{ min: 280, max: 360 }` |\n| `wind.unit` | `string \\| null` | Unidade original do grupo. | `\"KT\"`, `\"MPS\"`, `\"KMH\"` |\n| `wind.speedOperator` | `\"P\" \\| null` | Operador de velocidade maior que o valor. | `\"P\"` |\n| `wind.gustOperator` | `\"P\" \\| null` | Operador de rajada maior que o valor. | `\"P\"` |\n| `wind.calm` | `boolean` | `true` para `00000KT`. | `true` |\n\n## Visibilidade\n\n### Bloco principal\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `visibility.prevailing` | `PrevailingVisibility \\| null` | Visibilidade predominante. | `{ raw: \"9999\", value: 9999, unit: \"m\", greaterThan: false, lessThan: false, unavailable: false }` |\n| `visibility.minimum` | `DirectionalVisibility \\| null` | Visibilidade mínima direcional. | `{ raw: \"2000SW\", value: 2000, direction: \"SW\", unit: \"m\" }` |\n| `visibility.vertical` | `VerticalVisibility \\| null` | Visibilidade vertical a partir de `VV`. | `{ raw: \"VV002\", value: 200, unit: \"ft\", unavailable: false }` |\n\n### Visibilidade predominante\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `visibility.prevailing.raw` | `string` | Grupo bruto. | `\"1 3/4SM\"` |\n| `visibility.prevailing.value` | `number \\| null` | Valor numérico. | `9999`, `1.75` |\n| `visibility.prevailing.unit` | `\"m\" \\| \"SM\"` | Unidade. | `\"m\"`, `\"SM\"` |\n| `visibility.prevailing.greaterThan` | `boolean` | `true` para grupos como `P6SM`. | `true` |\n| `visibility.prevailing.lessThan` | `boolean` | `true` para grupos como `M1/4SM`. | `true` |\n| `visibility.prevailing.unavailable` | `boolean` | `true` para `////`. | `true` |\n\n### Visibilidade mínima direcional\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `visibility.minimum.raw` | `string` | Grupo bruto. | `\"2000SW\"` |\n| `visibility.minimum.value` | `number` | Valor numérico. | `2000` |\n| `visibility.minimum.direction` | `\"N\" \\| \"NE\" \\| \"E\" \\| \"SE\" \\| \"S\" \\| \"SW\" \\| \"W\" \\| \"NW\"` | Direção associada. | `\"SW\"` |\n| `visibility.minimum.unit` | `\"m\"` | Unidade. | `\"m\"` |\n\n### Visibilidade vertical\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `visibility.vertical.raw` | `string` | Grupo bruto. | `\"VV002\"` |\n| `visibility.vertical.value` | `number \\| null` | Valor em pés. | `200` |\n| `visibility.vertical.unit` | `\"ft\"` | Unidade. | `\"ft\"` |\n| `visibility.vertical.unavailable` | `boolean` | `true` para `VV///`. | `false` |\n\n## RVR\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `rvr[].raw` | `string` | Grupo bruto de RVR. | `\"R27L/0800N\"` |\n| `rvr[].runway` | `string` | Pista no formato `Rxx`. | `\"R27\"` |\n| `rvr[].direction` | `\"L\" \\| \"R\" \\| \"C\" \\| null` | Lado da pista. | `\"L\"` |\n| `rvr[].separator` | `\"/\"` | Separador interno do grupo. | `\"/\"` |\n| `rvr[].minIndicator` | `\"P\" \\| \"M\" \\| null` | Operador do valor mínimo. | `\"P\"` |\n| `rvr[].minValue` | `string \\| null` | Valor mínimo. | `\"2000\"` |\n| `rvr[].variableIndicator` | `\"V\" \\| null` | Indica faixa variável. | `\"V\"` |\n| `rvr[].maxIndicator` | `\"P\" \\| \"M\" \\| null` | Operador do valor máximo. | `\"M\"` |\n| `rvr[].maxValue` | `string \\| null` | Valor máximo. | `\"1000\"` |\n| `rvr[].trend` | `\"N\" \\| \"U\" \\| \"D\" \\| null` | Tendência do RVR. | `\"N\"` |\n| `rvr[].unitsOfMeasure` | `\"FT\" \\| \"M\" \\| null` | Unidade explicitamente declarada. | `\"FT\"` |\n| `rvr[].unit` | `string` | Unidade final normalizada. | `\"m\"`, `\"FT\"` |\n\n## Estado de pista\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `runwayState[].raw` | `string` | Grupo bruto de estado de pista. | `\"R25/190063\"` |\n| `runwayState[].runway` | `string` | Pista no formato `Rxx`. | `\"R25\"` |\n| `runwayState[].direction` | `\"L\" \\| \"R\" \\| \"C\" \\| null` | Lado da pista. | `null` |\n| `runwayState[].cleared` | `boolean` | `true` para grupos `CLRD`. | `false` |\n| `runwayState[].fromRunway` | `string \\| null` | Código `from runway` em grupos `CLRD`. | `\"12\"` |\n| `runwayState[].depositCode` | `string \\| null` | Código de depósito. | `\"1\"` |\n| `runwayState[].contaminationCode` | `string \\| null` | Código de contaminação. | `\"9\"` |\n| `runwayState[].depthCode` | `string \\| null` | Código de profundidade. | `\"00\"` |\n| `runwayState[].frictionCode` | `string \\| null` | Código de frenagem/fricção. | `\"63\"` |\n\n## Weather\n\n`weather` representa grupos meteorológicos completos. Isso evita perder a relação entre intensidade, descritor e fenômenos.\n\nExemplo:\n\n```txt\n-TSRA BR\n```\n\nSaída:\n\n```json\n[\n  {\n    \"raw\": \"-TSRA\",\n    \"intensity\": \"-\",\n    \"descriptor\": \"TS\",\n    \"phenomena\": [{ \"code\": \"RA\", \"description\": \"rain\" }]\n  },\n  {\n    \"raw\": \"BR\",\n    \"phenomena\": [{ \"code\": \"BR\", \"description\": \"mist\" }]\n  }\n]\n```\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `weather[].raw` | `string` | Grupo meteorológico bruto. | `\"-TSRA\"` |\n| `weather[].intensity` | `string \\| null` | Intensidade `-` ou `+`. | `\"-\"` |\n| `weather[].intensityDescription` | `string \\| null` | Descrição da intensidade. | `\"light intensity\"` |\n| `weather[].descriptor` | `string \\| null` | Descritor do grupo. | `\"TS\"`, `\"SH\"`, `\"FZ\"` |\n| `weather[].descriptorDescription` | `string \\| null` | Descrição do descritor. | `\"thunderstorm\"` |\n| `weather[].proximity` | `string \\| null` | Código de proximidade, hoje `VC`. | `\"VC\"` |\n| `weather[].proximityDescription` | `string \\| null` | Descrição da proximidade. | `\"in the vicinity\"` |\n| `weather[].phenomena` | `WeatherPhenomenon[]` | Fenômenos do grupo. | `[{ code: \"RA\", description: \"rain\" }]` |\n| `weather[].phenomena[].code` | `string` | Código do fenômeno. | `\"RA\"`, `\"BR\"`, `\"PY\"` |\n| `weather[].phenomena[].description` | `string` | Descrição do fenômeno. | `\"rain\"` |\n\n## Tendências\n\nOs subblocos internos de `trend` reutilizam a mesma semântica de `wind`, `visibility.prevailing`, `weather` e `clouds`.\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `trend[].raw` | `string` | Grupo bruto de tendência. | `\"TEMPO FM1430 TL1530 4000 SHRA BKN014\"` |\n| `trend[].type` | `\"NOSIG\" \\| \"BECMG\" \\| \"TEMPO\"` | Tipo da tendência. | `\"TEMPO\"` |\n| `trend[].timeIndicators` | `TrendTimeIndicator[]` | Indicadores temporais. | `[{ raw: \"FM1430\", kind: \"FM\", value: \"1430\" }]` |\n| `trend[].wind` | `WindGroup \\| null` | Vento específico da tendência. | `{ raw: \"25015KT\", ... }` |\n| `trend[].visibility` | `PrevailingVisibility \\| null` | Visibilidade da tendência. | `{ raw: \"4000\", value: 4000, unit: \"m\", greaterThan: false, lessThan: false, unavailable: false }` |\n| `trend[].weather` | `WeatherGroup[]` | Weather da tendência. | `[{ raw: \"SHRA\", ... }]` |\n| `trend[].clouds` | `CloudGroup[]` | Nuvens da tendência. | `[{ raw: \"BKN014\", ... }]` |\n| `trend[].cavok` | `boolean` | `true` se a tendência trouxer `CAVOK`. | `false` |\n| `trend[].unparsedTokens` | `string[]` | Tokens não reconhecidos dentro da tendência. | `[]` |\n\n### Indicadores de tempo da tendência\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `trend[].timeIndicators[].raw` | `string` | Grupo bruto do indicador. | `\"TL1530\"` |\n| `trend[].timeIndicators[].kind` | `\"FM\" \\| \"TL\" \\| \"AT\"` | Tipo do indicador. | `\"FM\"` |\n| `trend[].timeIndicators[].value` | `string` | Valor horário sem separadores. | `\"1430\"` |\n\n## Nuvens\n\n`VV` não entra em `clouds`. Ele é exposto em `visibility.vertical`.\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `clouds[].raw` | `string` | Grupo bruto de nuvem. | `\"BKN040CB\"` |\n| `clouds[].abbreviation` | `\"NCD\" \\| \"NSC\" \\| \"SKC\" \\| \"CLR\" \\| \"FEW\" \\| \"SCT\" \\| \"BKN\" \\| \"OVC\" \\| \"CB\"` | Código principal do grupo. | `\"BKN\"` |\n| `clouds[].meaning` | `string` | Descrição textual. | `\"broken\"` |\n| `clouds[].altitude` | `number \\| null` | Base em pés. | `4000` |\n| `clouds[].cumulonimbus` | `boolean` | Marca `CB`. | `true` |\n| `clouds[].toweringCumulus` | `boolean` | Marca `TCU`. | `true` |\n| `clouds[].type` | `\"clear\" \\| \"layer\" \\| \"obscuredCb\"` | Subtipo do grupo. | `\"layer\"` |\n| `clouds[].baseUnavailable` | `boolean` | Disponível apenas em grupos `layer`; indica base `///`. | `false` |\n| `clouds[].convectiveType` | `\"CB\" \\| \"TCU\" \\| null` | Disponível apenas em grupos `layer`; tipo convectivo. | `\"CB\"` |\n| `clouds[].convectiveTypeUnavailable` | `true \\| undefined` | Disponível apenas em grupos `layer`; `true` quando o tipo convectivo veio como `///`. | `true` |\n| `clouds[].unavailable` | `true` | Disponível apenas em `obscuredCb`; indica nuvem obscurecida. | `true` |\n\n## Temperatura e altímetro\n\n### Temperatura\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `temperature.raw` | `string \\| null` | Grupo bruto de temperatura/dew point. | `\"M07/M09\"` |\n| `temperature.air` | `number \\| null` | Temperatura do ar em Celsius. | `-7` |\n| `temperature.dewpoint` | `number \\| null` | Dew point em Celsius. | `-9` |\n\n### Altímetro\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `altimeter.raw` | `string \\| null` | Grupo bruto do altímetro. | `\"A2992\"` |\n| `altimeter.value` | `number \\| null` | Valor na unidade original. | `29.92`, `1012` |\n| `altimeter.unit` | `\"hPa\" \\| \"inHg\" \\| null` | Unidade original. | `\"inHg\"` |\n| `altimeter.inHg` | `number \\| null` | Valor calculado em polegadas de mercúrio. | `29.92` |\n| `altimeter.hPa` | `number \\| null` | Valor calculado em hectopascais. | `1013` |\n\n## Grupos suplementares\n\n### Recent weather\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `recentWeather[].raw` | `string` | Grupo bruto de tempo recente. | `\"RERA\"` |\n| `recentWeather[].code` | `string` | Código completo do grupo. | `\"RERA\"` |\n| `recentWeather[].description` | `string \\| null` | Descrição textual, quando conhecida. | `\"moderate or heavy rain\"` |\n\n### Wind shear\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `windShear[].raw` | `string` | Grupo bruto de wind shear. | `\"WS R27L\"` |\n| `windShear[].allRunways` | `boolean` | `true` para `WS ALL RWY`. | `true` |\n| `windShear[].runway` | `string \\| null` | Identificador da pista sem o prefixo `R`. | `\"27L\"` |\n\n### Sea state\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `seaState.raw` | `string` | Grupo bruto do estado do mar. | `\"W18/H015\"` |\n| `seaState.seaSurfaceTemperatureC` | `number \\| null` | Temperatura da superfície do mar em Celsius. | `18` |\n| `seaState.seaConditionCode` | `number \\| null` | Código de estado do mar. | `4` |\n| `seaState.waveHeightDm` | `number \\| null` | Altura de onda em decímetros. | `15` |\n\n### Remarks\n\n`remarks` preserva o conteúdo após `RMK` e enriquece apenas os subgrupos suportados.\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `remarks.raw` | `string` | Conteúdo bruto após `RMK`. | `\"AUT QFE750\"` |\n| `remarks.tokens` | `string[]` | Tokens do bloco `RMK`. | `[\"AUT\", \"QFE750\"]` |\n| `remarks.automatic` | `boolean` | `true` quando `AUT` aparece em `RMK`. | `true` |\n| `remarks.qfe` | `QfeGroup \\| null` | QFE parseado quando presente. | `{ raw: \"QFE750\", value: 750, unit: \"mmHg\", description: \"field elevation pressure\" }` |\n| `remarks.unparsedTokens` | `string[]` | Tokens ainda não decodificados semanticamente. | `[\"AO2\", \"SLP159\", \"$\"]` |\n\n### QFE em `remarks`\n\n| Propriedade | Tipo | Descrição | Exemplo |\n| --- | --- | --- | --- |\n| `remarks.qfe.raw` | `string` | Grupo bruto de QFE. | `\"QFE762\"` |\n| `remarks.qfe.value` | `number` | Valor numérico. | `762` |\n| `remarks.qfe.unit` | `\"mmHg\" \\| \"hPa\"` | Unidade inferida pelo tamanho do número. | `\"mmHg\"` |\n| `remarks.qfe.description` | `string` | Descrição textual. | `\"field elevation pressure\"` |\n\n## Compatibilidade\n\n- ESM: suportado\n- Web bundlers: suportado\n- React Native: suportado\n- HTML puro via bundle global: suportado\n\n","readmeFilename":"README.md"}