klio 1.5.4 → 1.5.6

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 CHANGED
@@ -118,8 +118,12 @@ It's possible to analyze a csv with a column of either ISO date time or unix tim
118
118
 
119
119
  - **Show house and sign distribution of the datetime column**: `klio [planet] --csv <file-path>`
120
120
  - **Show aspect type distribution between two planets:** `klio [planet1] [planet2] --csv <file-path> --a`
121
+ - **Specify date column name:** `klio [planet] --csv <file-path> --date-col "Buchungsdatum"` (e.g., `--date-col "Date"`)
121
122
  - **Filter CSV data by column value:** `klio [planet] --csv <file-path> --filter "column:value"` (e.g., `--filter "Item:coffee"`)
123
+ - **Filter CSV data by contains operator:** `klio [planet] --csv <file-path> --filter "column*text"` (e.g., `--filter "Buchungstext*Gutschrift"`)
124
+ - **Filter CSV data by excludes operator:** `klio [planet] --csv <file-path> --filter "column!text"` (e.g., `--filter "Buchungstext!Gutschrift"`)
122
125
  - **Filter CSV data by multiple conditions:** `klio [planet] --csv <file-path> --filter "column1:value1,column2:value2"` (e.g., `--filter "FTR:H,HomeTeam:Liverpool"`)
126
+ - **Filter CSV data with comparison operators:** `klio [planet] --csv <file-path> --filter "column>value"` (e.g., `--filter "Amount>100"`)
123
127
  - **Creating a bar chart**: Create a bar chart and save the image to the downloads' folder. The image shows the aspect distribution of your csv datetime values: `klio moon sun --csv /home/user/Downloads/coffee.csv --filter "Item:cookie" --a --title "Eaten cookies during sun-moon aspects"`
124
128
 
125
129
  - The command also returns a Chi-Square.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klio",
3
- "version": "1.5.4",
3
+ "version": "1.5.6",
4
4
  "description": "A CLI for astrological calculations",
5
5
  "main": "src/main.js",
6
6
  "bin": {
@@ -9,7 +9,8 @@ const planets = {
9
9
  saturn: 6,
10
10
  uranus: 7,
11
11
  neptune: 8,
12
- pluto: 9
12
+ pluto: 9,
13
+ chiron: 15
13
14
  };
14
15
 
15
16
  // Zodiac signs (English)
@@ -49,7 +50,8 @@ const dignities = {
49
50
  6: { sign: 'Capricorn', exaltation: 'Libra', fall: 'Aries', detriment: 'Cancer' }, // Saturn
50
51
  7: { sign: 'Aquarius', exaltation: 'Sagittarius', fall: 'Leo', detriment: 'Taurus' }, // Uranus
51
52
  8: { sign: 'Pisces', exaltation: 'Leo', fall: 'Aquarius', detriment: 'Virgo' }, // Neptune
52
- 9: { sign: 'Scorpio', exaltation: 'Aries', fall: 'Taurus', detriment: 'Scorpio' } // Pluto
53
+ 9: { sign: 'Scorpio', exaltation: 'Aries', fall: 'Taurus', detriment: 'Scorpio' }, // Pluto
54
+ 15: { sign: 'Virgo', exaltation: 'Pisces', fall: 'Virgo', detriment: 'Pisces' } // Chiron
53
55
  };
54
56
 
55
57
  module.exports = {
@@ -1859,7 +1859,7 @@ function parseFilterCriteria(filterString) {
1859
1859
  const filterConditions = filterString.split(',').map(cond => cond.trim());
1860
1860
 
1861
1861
  const criteria = [];
1862
- const operatorRegex = /^(.+?)\s*(>=|<=|!=|=|>|<)\s*(.+)$/;
1862
+ const operatorRegex = /^(.+?)\s*(>=|<=|!=|=|>|<|\*|!)\s*(.+)$/;
1863
1863
 
1864
1864
  for (const condition of filterConditions) {
1865
1865
  const operatorMatch = condition.match(operatorRegex);
@@ -1872,6 +1872,27 @@ function parseFilterCriteria(filterString) {
1872
1872
  continue;
1873
1873
  }
1874
1874
 
1875
+ // Check for contains (*) or excludes (!) operators in the value part
1876
+ const containsMatch = condition.match(/^(.+?):\*(.+)$/);
1877
+ if (containsMatch) {
1878
+ criteria.push({
1879
+ column: containsMatch[1].trim(),
1880
+ operator: '*',
1881
+ value: containsMatch[2].trim()
1882
+ });
1883
+ continue;
1884
+ }
1885
+
1886
+ const excludesMatch = condition.match(/^(.+?):!(.+)$/);
1887
+ if (excludesMatch) {
1888
+ criteria.push({
1889
+ column: excludesMatch[1].trim(),
1890
+ operator: '!',
1891
+ value: excludesMatch[2].trim()
1892
+ });
1893
+ continue;
1894
+ }
1895
+
1875
1896
  const parts = condition.split(':');
1876
1897
  if (parts.length !== 2) {
1877
1898
  console.warn(`Invalid filter format. Expected "column:value" or "column > value" but got "${condition}"`);
@@ -1919,6 +1940,12 @@ function applyFilter(records, filterCriteria) {
1919
1940
  return bothNumeric ? recordNum < valueNum : false;
1920
1941
  case '<=':
1921
1942
  return bothNumeric ? recordNum <= valueNum : false;
1943
+ case '*':
1944
+ // Contains operator - check if record value contains the search string
1945
+ return recordValueStr.includes(valueStr);
1946
+ case '!':
1947
+ // Excludes operator - check if record value does NOT contain the search string
1948
+ return !recordValueStr.includes(valueStr);
1922
1949
  default:
1923
1950
  return false;
1924
1951
  }
@@ -1941,7 +1968,7 @@ function applyFilter(records, filterCriteria) {
1941
1968
  }
1942
1969
  }
1943
1970
 
1944
- function analyzeCSVWithDatetime(filePath, planetName = 'moon', houseSystem = 'koch', analyzeAspects = false, partnerPlanet = null, filterCriteria = null) {
1971
+ function analyzeCSVWithDatetime(filePath, planetName = 'moon', houseSystem = 'koch', analyzeAspects = false, partnerPlanet = null, filterCriteria = null, dateColumn = null) {
1945
1972
  return new Promise(async (resolve, reject) => {
1946
1973
  const results = [];
1947
1974
  let pendingOperations = 0;
@@ -2014,8 +2041,25 @@ function analyzeCSVWithDatetime(filePath, planetName = 'moon', houseSystem = 'ko
2014
2041
 
2015
2042
  // Process each row
2016
2043
  for (const data of filteredRecords) {
2017
- // Look for a column with datetime values, prioritizing specific date formats
2018
- const datetimeColumns = [];
2044
+ // Use specified date column if provided, otherwise auto-detect
2045
+ let datetimeColumns = [];
2046
+ let datetimeValue = null;
2047
+
2048
+ if (dateColumn) {
2049
+ // Use the specified date column
2050
+ if (data.hasOwnProperty(dateColumn)) {
2051
+ datetimeValue = data[dateColumn];
2052
+ datetimeColumns = [dateColumn];
2053
+ } else {
2054
+ console.warn(`⚠️ Specified date column "${dateColumn}" not found in CSV. Trying auto-detection...`);
2055
+ // Fall back to auto-detection
2056
+ }
2057
+ }
2058
+
2059
+ // If no date column was specified or it wasn't found, auto-detect
2060
+ if (datetimeColumns.length === 0) {
2061
+ // Look for a column with datetime values, prioritizing specific date formats
2062
+ datetimeColumns = [];
2019
2063
 
2020
2064
  // First pass: look for YYYY-MM-DD format (most specific)
2021
2065
  const yyyyMmDdColumns = Object.keys(data).filter(key => {
@@ -2049,11 +2093,15 @@ function analyzeCSVWithDatetime(filePath, planetName = 'moon', houseSystem = 'ko
2049
2093
  return moment(trimmed, moment.ISO_8601, true).isValid();
2050
2094
  });
2051
2095
 
2052
- // Prioritize columns: YYYY-MM-DD, DD/MM/YYYY, Unix timestamps, then ISO dates
2053
- datetimeColumns.push(...yyyyMmDdColumns, ...ddMmYyyyColumns, ...unixTimestampColumns, ...isoDateColumns);
2096
+ // Prioritize columns: YYYY-MM-DD, DD/MM/YYYY, Unix timestamps, then ISO dates
2097
+ datetimeColumns.push(...yyyyMmDdColumns, ...ddMmYyyyColumns, ...unixTimestampColumns, ...isoDateColumns);
2098
+
2099
+ if (datetimeColumns.length > 0) {
2100
+ datetimeValue = data[datetimeColumns[0]];
2101
+ }
2102
+ }
2054
2103
 
2055
- if (datetimeColumns.length > 0) {
2056
- const datetimeValue = data[datetimeColumns[0]];
2104
+ if (datetimeColumns.length > 0 && datetimeValue !== null) {
2057
2105
  const datetimeValueTrimmed = datetimeValue != null ? datetimeValue.toString().trim() : '';
2058
2106
  let datetime;
2059
2107
 
@@ -2249,9 +2297,25 @@ function analyzeCSVWithDatetime(filePath, planetName = 'moon', houseSystem = 'ko
2249
2297
 
2250
2298
  // Process each record
2251
2299
  for (const data of filteredRecords) {
2252
-
2253
- // Look for a column with ISO-Datetime values, YYYY-MM-DD dates, DD/MM/YYYY dates (optional time), or Unix-Timestamps
2254
- const datetimeColumns = Object.keys(data).filter(key => {
2300
+ // Use specified date column if provided, otherwise auto-detect
2301
+ let datetimeColumns = [];
2302
+ let datetimeValue = null;
2303
+
2304
+ if (dateColumn) {
2305
+ // Use the specified date column
2306
+ if (data.hasOwnProperty(dateColumn)) {
2307
+ datetimeValue = data[dateColumn];
2308
+ datetimeColumns = [dateColumn];
2309
+ } else {
2310
+ console.warn(`⚠️ Specified date column "${dateColumn}" not found in CSV. Trying auto-detection...`);
2311
+ // Fall back to auto-detection
2312
+ }
2313
+ }
2314
+
2315
+ // If no date column was specified or it wasn't found, auto-detect
2316
+ if (datetimeColumns.length === 0) {
2317
+ // Look for a column with ISO-Datetime values, YYYY-MM-DD dates, DD/MM/YYYY dates (optional time), or Unix-Timestamps
2318
+ datetimeColumns = Object.keys(data).filter(key => {
2255
2319
  const value = data[key];
2256
2320
  const trimmed = value != null ? value.toString().trim() : '';
2257
2321
  // Check for ISO-8601 date
@@ -2265,8 +2329,12 @@ function analyzeCSVWithDatetime(filePath, planetName = 'moon', houseSystem = 'ko
2265
2329
  return isISO || isYYYYMMDD || isDDMMYYYY || isUnixTimestamp;
2266
2330
  });
2267
2331
 
2268
- if (datetimeColumns.length > 0) {
2269
- const datetimeValue = data[datetimeColumns[0]];
2332
+ if (datetimeColumns.length > 0) {
2333
+ datetimeValue = data[datetimeColumns[0]];
2334
+ }
2335
+ }
2336
+
2337
+ if (datetimeColumns.length > 0 && datetimeValue !== null) {
2270
2338
  const datetimeValueTrimmed = datetimeValue != null ? datetimeValue.toString().trim() : '';
2271
2339
  let datetime;
2272
2340
 
package/src/cli/cli.js CHANGED
@@ -392,6 +392,7 @@ program
392
392
  .option('--v <count>', 'Shows past aspects between two planets (Format: --v <count> planet1 aspectType planet2)')
393
393
  .option('--z <count>', 'Shows future aspects between two planets (Format: --z <count> planet1 aspectType planet2)')
394
394
  .option('--csv <filepath>', 'Analyzes a CSV file with ISO-Datetime values or Unix timestamps')
395
+ .option('--date-col <column>', 'Specifies the column name containing date values (e.g., --date-col "Buchungsdatum")')
395
396
  .option('--filter <column:value>', 'Filters CSV data by column:value (e.g., --filter "Item:coffee")')
396
397
  .option('--title <title>', 'Title for the chart image (generates PNG image when provided)')
397
398
  .option('--in [count]', 'Shows next planet ingress (entering new sign). Optional count for multiple ingresses')
@@ -1560,8 +1561,8 @@ program
1560
1561
  };
1561
1562
  }
1562
1563
 
1563
- // Check if we should use natal positions (when --i is used without custom date)
1564
- if (shouldUseBirthData(options) && !options.d) {
1564
+ // Check if we should use natal positions (when --i, --p1, --p2, --wp, or --up is used without custom date)
1565
+ if ((shouldUseBirthData(options) || shouldUsePersonData(options)) && !options.d) {
1565
1566
  useNatalPositions = true;
1566
1567
  customDate = birthData; // Use birth data for planet positions
1567
1568
  console.log('Using natal positions from birth data.');
@@ -1742,7 +1743,9 @@ program
1742
1743
  const analyzeAspects = actualOptions.a || false;
1743
1744
  const filterCriteria = actualOptions.filter;
1744
1745
 
1745
- analyzeCSVWithDatetime(actualOptions.csv, planet, houseSystem, analyzeAspects, planet2, filterCriteria)
1746
+ const dateColumn = actualOptions.dateCol;
1747
+
1748
+ analyzeCSVWithDatetime(actualOptions.csv, planet, houseSystem, analyzeAspects, planet2, filterCriteria, dateColumn)
1746
1749
  .then(({ results, houseDistribution, signDistribution, aspectStatistics }) => {
1747
1750
  if (results.length === 0) {
1748
1751
  console.log('No valid ISO-Datetime values found in the CSV file.');
@@ -2785,7 +2788,9 @@ program
2785
2788
  const analyzeAspects = actualOptions.a || false;
2786
2789
  const filterCriteria = actualOptions.filter;
2787
2790
 
2788
- analyzeCSVWithDatetime(actualOptions.csv, planet, houseSystem, analyzeAspects, planet2, filterCriteria)
2791
+ const dateColumn = actualOptions.dateCol;
2792
+
2793
+ analyzeCSVWithDatetime(actualOptions.csv, planet, houseSystem, analyzeAspects, planet2, filterCriteria, dateColumn)
2789
2794
  .then(({ results, houseDistribution, signDistribution, aspectStatistics }) => {
2790
2795
  if (results.length === 0) {
2791
2796
  console.log('No valid ISO-Datetime values found in the CSV file.');