New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@fboes/aerofly-patterns

Package Overview
Dependencies
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fboes/aerofly-patterns - npm Package Compare versions

Comparing version 2.2.0 to 2.3.0

dist/lib/AviationWeatherApi.test.js

8

CHANGELOG.md
# Changelog
## 2.3.0
- Added API changes from AviationWeather
- Added approximate alignment for water runways
- Added extra cloud layers
- Extracted FileWriter to have NodeJs dependency separate
- Improved `DateYielder`
## 2.2.0

@@ -4,0 +12,0 @@

2

dist/data/Airports.js

@@ -38,2 +38,3 @@ // @ts-check

KHAF: { runways: [{ id: "30", isRightPattern: true }] },
KJAC: { minimumSafeAltitude: 14_900, runways: [{ id: "19", ilsFrequency: 109.1, isPreferred: true }] },
KMVY: {

@@ -52,2 +53,3 @@ runways: [

},
KWYS: { minimumSafeAltitude: 12_600, runways: [{ id: "01", ilsFrequency: 110.7, isPreferred: true }] },
};

7

dist/index.js

@@ -6,2 +6,3 @@ #!/usr/bin/env node

import { Configuration } from "./lib/Configuration.js";
import { FileWriter } from "./lib/FileWriter.js";

@@ -12,3 +13,3 @@ const configuration = new Configuration(process.argv);

process.stdout
.write(`\x1b[94mUsage: npx @fboes/aerofly-patterns ICAO_AIRPORT_CODE [AEROFLY_AIRCRAFT_CODE] [...options]\x1b[0m
.write(`\x1b[94mUsage: npx @fboes/aerofly-patterns@latest ICAO_AIRPORT_CODE [AEROFLY_AIRCRAFT_CODE] [...options]\x1b[0m
Create landing pattern lessons for Aerofly FS 4.

@@ -28,3 +29,5 @@

const app = new AeroflyPatterns(configuration);
await app.build(process.cwd());
await app.build();
await FileWriter.writeFile(app, process.cwd());
console.log(`✅ Done with ${app.airport?.name} (${app.airport?.id})`);
// @ts-check
import { AirportTest } from "./lib/Airport.test.js";
import { AviationWeatherApiTest, AviationWeatherApiHelpersTest } from "./lib/AviationWeatherApi.test.js";
import { DateYielderTest } from "./lib/DateYielder.test.js";

@@ -8,4 +9,6 @@ import { DegreeTest } from "./lib/Degree.test.js";

new AirportTest();
new AviationWeatherApiTest();
new AviationWeatherApiHelpersTest();
new DateYielderTest();
new DegreeTest();
new FormatterTest();
// @ts-check
import * as fs from "node:fs/promises";
import { Airport } from "./Airport.js";

@@ -52,7 +51,3 @@ import { AviationWeatherApi } from "./AviationWeatherApi.js";

/**
*
* @param {string} saveDirectory
*/
async build(saveDirectory) {
async build() {
const airport = await AviationWeatherApi.fetchAirports([this.configuration.icaoCode]);

@@ -82,4 +77,2 @@ if (!airport.length) {

}
await this.writeCustomMissionFiles(saveDirectory);
}

@@ -111,2 +104,3 @@

alignment: r.alignment,
dimension: r.dimension,
frequency: r.ilsFrequency,

@@ -229,2 +223,3 @@ isRightPattern: r.isRightPattern,

<[string8u] [aircraft_name] [${s.aircraft.aeroflyCode}]>
//<[string8u][aircraft_livery] []>
<[stringt8c] [aircraft_icao] [${s.aircraft.data.icaoCode}]>

@@ -252,4 +247,8 @@ <[stringt8c] [callsign] [${s.aircraft.data.callsign}]>

<[float64][visibility][${(s.weather?.visibility ?? 15) * Units.meterPerStatuteMile}]>
<[float64][cloud_cover][${s.weather?.cloudCover ?? 0}]>
<[float64][cloud_base][${(s.weather?.cloudBase ?? 0) / Units.feetPerMeter}]>
<[float64][cloud_cover][${s.weather?.clouds[0]?.cloudCover ?? 0}]> // ${s.weather?.clouds[0]?.cloudCoverCode ?? "CLR"}
<[float64][cloud_base][${(s.weather?.clouds[0]?.cloudBase ?? 0) / Units.feetPerMeter}]> // ${s.weather?.clouds[0]?.cloudBase ?? 0} ft
//<[float64][cloud2_cover][${s.weather?.clouds[1]?.cloudCover ?? 0}]> // ${s.weather?.clouds[1]?.cloudCoverCode ?? "CLR"}
//<[float64][cloud2_base][${(s.weather?.clouds[1]?.cloudBase ?? 0) / Units.feetPerMeter}]> // ${s.weather?.clouds[1]?.cloudBase ?? 0} ft
//<[float64][cloud3_cover][${s.weather?.clouds[2]?.cloudCover ?? 0}]> // ${s.weather?.clouds[2]?.cloudCoverCode ?? "CLR"}
//<[float64][cloud3_base][${(s.weather?.clouds[2]?.cloudBase ?? 0) / Units.feetPerMeter}]> // ${s.weather?.clouds[2]?.cloudBase ?? 0} ft
>

@@ -352,5 +351,5 @@ <[list_tmmission_checkpoint][checkpoints][]

const clouds =
s.weather?.cloudCoverCode !== "CLR"
? `${pad(s.weather?.cloudCoverCode, 3, true)} @ ${pad(s.weather?.cloudBase.toLocaleString("en"), 6, true)} ft`
: pad(s.weather?.cloudCoverCode, 15);
s.weather?.clouds[0]?.cloudCoverCode !== "CLR"
? `${pad(s.weather?.clouds[0]?.cloudCoverCode, 3, true)} @ ${pad(s.weather?.clouds[0]?.cloudBase.toLocaleString("en"), 6, true)} ft`
: pad(s.weather?.clouds[0]?.cloudCoverCode, 15);

@@ -362,3 +361,3 @@ output.push(

Formatter.getUtcCompleteDate(s.date),
pad(padNumber(lst) + ":00", 10, true),
pad(padNumber(lst) + ":" + padNumber(s.date.getUTCMinutes()), 10, true),
s.weather?.windSpeed === 0

@@ -390,25 +389,2 @@ ? pad("Calm", 12)

}
/**
*
* @param {string} saveDirectory
*/
async writeCustomMissionFiles(saveDirectory) {
if (this.configuration.directoryMode) {
saveDirectory = `${saveDirectory}/data/Landing_Challenges-${this.configuration.icaoCode}-${this.configuration.aircraft}`;
await fs.mkdir(saveDirectory, { recursive: true });
}
await Promise.all([
fs.writeFile(`${saveDirectory}/custom_missions_user.tmc`, this.buildCustomMissionTmc()),
!this.configuration.readme || fs.writeFile(`${saveDirectory}/README.md`, this.buildReadmeMarkdown()),
!this.configuration.geojson ||
fs.writeFile(
`${saveDirectory}/${this.configuration.icaoCode}-${this.configuration.aircraft}.geojson`,
JSON.stringify(this.buildGeoJson(), null, 2),
),
// fs.writeFile(`${saveDirectory}/debug.json`, JSON.stringify(this, null, 2)),
]);
}
}

@@ -8,2 +8,3 @@ // @ts-check

import { Formatter } from "./Formatter.js";
import { AviationWeatherApiHelpers } from "./AviationWeatherApi.js";

@@ -20,3 +21,3 @@ /**

constructor(airportJson, configuration = null) {
this.id = airportJson.id;
this.id = airportJson.icaoId;
this.position = new Point(airportJson.lon, airportJson.lat, airportJson.elev);

@@ -50,3 +51,3 @@

this.buildRunways(r, this.position, configuration).forEach((runway) => {
this.runways.push(runway);
runway && this.runways.push(runway);
});

@@ -79,6 +80,6 @@ });

this.magneticDeclination = 0;
const mag_dec_match = airportJson.mag_dec.match(/^(\d+)(E|W)$/);
if (mag_dec_match) {
this.magneticDeclination = Number(mag_dec_match[1]);
if (mag_dec_match[2] === "W") {
const magdecMatch = airportJson.magdec.match(/^(\d+)(E|W)$/);
if (magdecMatch) {
this.magneticDeclination = Number(magdecMatch[1]);
if (magdecMatch[2] === "W") {
this.magneticDeclination *= -1;

@@ -96,3 +97,3 @@ }

*/
this.hasTower = airportJson.tower !== "-";
this.hasTower = airportJson.tower === "T";

@@ -102,5 +103,5 @@ /**

*/
this.hasBeacon = airportJson.beacon !== "-";
this.hasBeacon = airportJson.beacon === "B";
const lclP = airportJson.freqs.find((f) => {
const lclP = AviationWeatherApiHelpers.fixFrequencies(airportJson.freqs).find((f) => {
return f.type === "LCL/P";

@@ -112,3 +113,3 @@ });

*/
this.localFrequency = lclP ? lclP.freq : null;
this.localFrequency = lclP?.freq ?? null;

@@ -210,5 +211,12 @@ /**

// Helipads
const alignmentBase = runwayJson.alignment !== "-" ? Number(runwayJson.alignment) : 0;
// Helipads & Water runways get an approximate alignment
if (runwayJson.alignment === "-") {
runwayJson.alignment = id[0].replace(/\D/g, "") + "0";
}
const alignmentBase = Number(runwayJson.alignment);
if (isNaN(alignmentBase)) {
return [];
}
/**

@@ -215,0 +223,0 @@ * @type {[number, number]} both directions

@@ -16,9 +16,10 @@ //@ts-check

const airportJson = {
id: "KMCI",
icaoId: "KMCI",
name: "KANSAS CITY/KANSAS_CITY_INTL",
type: "ARP",
lat: 39.2976,
lon: -94.7139,
elev: 313.1,
mag_dec: "02E",
rwy_num: 3,
magdec: "02E",
rwyNum: 3,
tower: "T",

@@ -76,9 +77,10 @@ beacon: "B",

const airportJson = {
id: "KMVY",
icaoId: "KMVY",
name: "VINEYARD HAVEN/MARTHA'S_VINEYARD",
type: "ARP",
lat: 41.3934,
lon: -70.6139,
elev: 20.4,
mag_dec: "15W",
rwy_num: 2,
magdec: "15W",
rwyNum: 2,
tower: "T",

@@ -121,9 +123,10 @@ beacon: "B",

const airportJson = {
id: "KSCK",
icaoId: "KSCK",
name: "STOCKTON/STOCKTON_METRO",
type: "ARP",
lat: 37.8944,
lon: -121.2387,
elev: 10.1,
mag_dec: "14E",
rwy_num: 3,
magdec: "14E",
rwyNum: 3,
tower: "T",

@@ -130,0 +133,0 @@ beacon: "B",

@@ -32,6 +32,10 @@ // @ts-check

/**
* @typedef {"A"|"C"|"G"|"W"|"T"} AviationWeatherApiRunwaySurface "A" Asphalt, "C" Concrete, "G" Grass, "W" Water, "T" Turf Dirt
*/
/**
* @typedef {object} AviationWeatherApiRunway
* @property {string} id "01L/19R"
* @property {string} dimension "10801x150" in feet
* @property {"A"|"C"|"G"} surface "A" Asphalt, "C" Concrete, "G" Grass
* @property {AviationWeatherApiRunwaySurface} surface
* @property {string} alignment "013" or "-"

@@ -43,4 +47,4 @@ * @see https://aviationweather.gov/data/api/#/Data/dataAirport

* @typedef {object} AviationWeatherApiFrequencies
* @property {string} type "LCL/P",
* @property {number} freq 121.4
* @property {string} type "LCL/P" or "-"
* @property {number} [freq] 121.4
*/

@@ -50,13 +54,14 @@

* @typedef {object} AviationWeatherApiAirport
* @property {string} id "KMCI"
* @property {string} icaoId "KMCI"
* @property {string} name "KANSAS CITY/KANSAS_CITY_INTL"
* @property {"ARP"|"HEL"} type Airport, Heliport
* @property {number} lat
* @property {number} lon
* @property {number} elev 313.1 meters MSL
* @property {string} mag_dec "02E" for East
* @property {number} rwy_num
* @property {"T"|"-"} tower
* @property {"B"|"-"} beacon
* @property {string} magdec "02E" for East
* @property {number} rwyNum
* @property {"T"|"-"|null} tower
* @property {"B"|"-"|null} beacon
* @property {AviationWeatherApiRunway[]} runways
* @property {AviationWeatherApiFrequencies[]} freqs
* @property {AviationWeatherApiFrequencies[]|string} freqs or "LCL/P,123.9;ATIS,124.7"
* @see https://aviationweather.gov/data/api/#/Data/dataAirport

@@ -145,1 +150,29 @@ */

}
export class AviationWeatherApiHelpers {
/**
*
* @param {AviationWeatherApiFrequencies[]|string} freq
* @returns {AviationWeatherApiFrequencies[]}
*/
static fixFrequencies(freq) {
if (typeof freq !== "string") {
return freq;
}
return freq.split(";").map(
/**
*
* @param {string} f
* @returns {AviationWeatherApiFrequencies}
*/
(f) => {
const parts = f.split(",");
return {
type: parts[0],
freq: parts[1] ? Number(parts[1]) : undefined,
};
},
);
}
}

@@ -190,3 +190,3 @@ // @ts-check

/**
* @type {boolean}
* @type {boolean} if generate
*/

@@ -193,0 +193,0 @@ this.readme = Boolean(values["readme"]);

@@ -24,3 +24,3 @@ // @ts-check

*/
this.startDate = startDate;
this.startDate = this.getLocalTime(startDate, 12 - (count - 1) / 2);
}

@@ -36,8 +36,6 @@

while (index < this.count) {
const currenDate = new Date(this.startDate.getTime());
if (this.count > 1) {
const percentage = index / (this.count - 1);
currenDate.setDate(currenDate.getDate() - Math.round(percentage * 12) - 1);
currenDate.setUTCHours(8 - this.offsetHours + percentage * 12);
}
const currenDate = new Date(this.startDate);
currenDate.setDate(currenDate.getDate() - index);
currenDate.setUTCHours(currenDate.getUTCHours() + index);
yield currenDate;

@@ -48,2 +46,20 @@

}
/**
* Gets the next local 8 o'clock in the past
* @param {Date} startDate
* @param {number} hours local time
* @returns {Date}
*/
getLocalTime(startDate, hours = 6) {
const eightOClock = new Date(startDate);
eightOClock.setUTCMinutes(60 * (hours % 1));
eightOClock.setUTCHours(Math.floor(hours - this.offsetHours));
while (eightOClock.valueOf() > startDate.valueOf()) {
eightOClock.setDate(eightOClock.getDate() - 1);
}
return eightOClock;
}
}

@@ -8,19 +8,8 @@ //@ts-check

constructor() {
this.checkSingleEntry();
this.checkMultipleEntries(5);
this.checkMultipleEntries(12);
this.checkMultipleEntries(24);
}
checkSingleEntry() {
const startDate = new Date(Date.UTC(2024, 4, 15, 12, 0, 0));
const dateYielder = new DateYielder(1, 0, startDate);
const dates = dateYielder.entries();
for (const currentDate of dates) {
//console.log(currentDate);
assert.ok(currentDate);
assert.equal(currentDate.toISOString(), startDate.toISOString());
// All time zones
for (let i = 12; i >= -12; i--) {
this.checkEntries(1, i);
this.checkEntries(5, i);
this.checkEntries(12, i);
}
console.log(`✅ ${this.constructor.name}.checkSingleEntry successful`);
}

@@ -31,15 +20,20 @@

* @param {number} entries
* @param {number} offsetHours
*/
checkMultipleEntries(entries) {
const startDate = new Date(Date.UTC(2024, 4, 15, 12, 0, 0));
const dateYielder = new DateYielder(entries, 2, startDate);
const dates = dateYielder.entries();
for (const currentDate of dates) {
//console.log(currentDate);
assert.ok(currentDate);
assert.notEqual(currentDate.toISOString(), startDate.toISOString());
}
checkEntries(entries, offsetHours) {
const startDate = new Date(Date.UTC(2024, 4, 15, 12, 32, 0));
const dateYielder = new DateYielder(entries, offsetHours, startDate);
const dates = Array.from(dateYielder.entries());
console.log(`✅ ${this.constructor.name}.checkMultipleEntries(${entries}) successful`);
assert.strictEqual(dates.length, entries);
dates.forEach((d) => {
assert.strictEqual(d.getUTCFullYear(), 2024);
assert.strictEqual(d.getUTCMonth(), 4);
assert.ok(d.getUTCDate() <= 15);
assert.ok(d.valueOf() <= startDate.valueOf());
});
//console.log(dateYielder.startDate, dates);
console.log(`✅ ${this.constructor.name}.checkEntries(${entries}, ${offsetHours}) successful`);
}
}

@@ -134,3 +134,3 @@ // @ts-check

} else {
switch (weather.cloudCoverCode) {
switch (weather.clouds[0]?.cloudCoverCode) {
case "OVC":

@@ -137,0 +137,0 @@ adjectives.push("overcast");

@@ -5,3 +5,3 @@ //@ts-check

import { Formatter } from "./Formatter.js";
import { ScenarioWeather } from "./Scenario.js";
import { ScenarioWeather, ScenarioWeatherCloud } from "./Scenario.js";

@@ -78,3 +78,3 @@ export class FormatterTest {

w.cloudCoverCode = "OVC";
w.clouds[0] = new ScenarioWeatherCloud("OVC", 1000);
assert.strictEqual("foggy", Formatter.getWeatherAdjectives(w));

@@ -81,0 +81,0 @@

@@ -85,3 +85,3 @@ // @ts-check

if (!weather.length) {
throw new Error("No METAR information from API");
throw new Error("No METAR information from API for " + this.airport.id);
}

@@ -376,12 +376,2 @@ this.weather = new ScenarioWeather(weather[0]);

/**
* @type {number} 0..1
*/
#cloudCover = 0;
/**
* @type {"CLR"|"FEW"|"SCT"|"BKN"|"OVC"}
*/
#cloudCoverCode = "CLR";
/**
* @param {import('./AviationWeatherApi.js').AviationWeatherApiMetar} weatherJson

@@ -410,10 +400,7 @@ */

this.cloudCoverCode = weatherJson.clouds[0]?.cover;
this.clouds = weatherJson.clouds.map((c) => {
return new ScenarioWeatherCloud(c.cover, c.base);
});
/**
* @type {number} in ft
*/
this.cloudBase = weatherJson.clouds[0]?.base ?? 0;
/**
* @type {number} 0..1

@@ -430,4 +417,35 @@ */

}
}
export class ScenarioWeatherCloud {
/**
* @type {number} 0..1
*/
#cloudCover = 0;
/**
* @type {"CLR"|"FEW"|"SCT"|"BKN"|"OVC"}
*/
#cloudCoverCode = "CLR";
/**
* @param {"CAVOK"|"CLR"|"FEW"|"SCT"|"BKN"|"OVC"} cover
* @param {number?} base
*/
constructor(cover, base) {
this.cloudCoverCode = cover;
/**
* @type {number} in ft
*/
this.cloudBase = base ?? 0;
}
/**
* @returns {number} 0..1
*/
get cloudCover() {
return this.#cloudCover;
}
/**
*

@@ -462,9 +480,2 @@ * @param {"CAVOK"|"CLR"|"FEW"|"SCT"|"BKN"|"OVC"} cloudCoverCode

}
/**
* @returns {number} 0..1
*/
get cloudCover() {
return this.#cloudCover;
}
}
{
"name": "@fboes/aerofly-patterns",
"version": "2.2.0",
"version": "2.3.0",
"description": "Landegerät - Create landing pattern lessons for Aerofly FS 4.",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

@@ -25,3 +25,3 @@ # Aerofly Landegerät

```
Usage: npx @fboes/aerofly-patterns ICAO_AIRPORT_CODE [AEROFLY_AIRCRAFT_CODE] [...options]
Usage: npx @fboes/aerofly-patterns@latest ICAO_AIRPORT_CODE [AEROFLY_AIRCRAFT_CODE] [...options]
Create landing pattern lessons for Aerofly FS 4.

@@ -28,0 +28,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc