chart2txt 0.5.1 → 0.6.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.
Files changed (39) hide show
  1. package/dist/chart2txt.min.js +1 -1
  2. package/dist/config/ChartSettings.d.ts +1 -0
  3. package/dist/config/ChartSettings.js +1 -0
  4. package/dist/constants.js +4 -2
  5. package/dist/core/aspectPatterns.d.ts +5 -0
  6. package/dist/core/aspectPatterns.js +444 -0
  7. package/dist/core/aspects.js +94 -6
  8. package/dist/core/astrology.d.ts +8 -2
  9. package/dist/core/astrology.js +23 -6
  10. package/dist/core/dignities.d.ts +27 -0
  11. package/dist/core/dignities.js +136 -0
  12. package/dist/core/dispositors.d.ts +22 -0
  13. package/dist/core/dispositors.js +143 -0
  14. package/dist/core/signDistributions.d.ts +31 -0
  15. package/dist/core/signDistributions.js +150 -0
  16. package/dist/formatters/text/sections/angles.js +4 -4
  17. package/dist/formatters/text/sections/aspectPatterns.d.ts +7 -0
  18. package/dist/formatters/text/sections/aspectPatterns.js +175 -0
  19. package/dist/formatters/text/sections/aspects.js +7 -4
  20. package/dist/formatters/text/sections/birthdata.js +1 -1
  21. package/dist/formatters/text/sections/dispositors.d.ts +7 -0
  22. package/dist/formatters/text/sections/dispositors.js +20 -0
  23. package/dist/formatters/text/sections/houseOverlays.js +10 -34
  24. package/dist/formatters/text/sections/houses.d.ts +6 -0
  25. package/dist/formatters/text/sections/houses.js +36 -0
  26. package/dist/formatters/text/sections/planets.js +11 -26
  27. package/dist/formatters/text/sections/signDistributions.d.ts +25 -0
  28. package/dist/formatters/text/sections/signDistributions.js +67 -0
  29. package/dist/formatters/text/textFormatter.js +37 -3
  30. package/dist/types.d.ts +61 -0
  31. package/dist/utils/formatting.d.ts +6 -0
  32. package/dist/utils/formatting.js +13 -0
  33. package/dist/utils/houseCalculations.d.ts +13 -0
  34. package/dist/utils/houseCalculations.js +65 -0
  35. package/dist/utils/precision.d.ts +49 -0
  36. package/dist/utils/precision.js +71 -0
  37. package/dist/utils/validation.d.ts +37 -0
  38. package/dist/utils/validation.js +181 -0
  39. package/package.json +2 -1
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.chart2txt=t():e.chart2txt=t()}(this,(()=>(()=>{"use strict";var e={75:(e,t)=>{function n(e,t,n,r){let s=Math.abs(t.degree-n.degree);s>180&&(s=360-s);let a=null;for(const o of e){const e=Math.abs(s-o.angle);if(r){const e=Math.floor(t.degree/30),r=Math.floor(n.degree/30),s=Math.floor(o.angle/30);if(Math.abs(e-r)!==s)continue}e<=o.orb&&(!a||e<a.orb)&&(a={planetA:t.name,planetB:n.name,aspectType:o.name,orb:e})}return a}Object.defineProperty(t,"__esModule",{value:!0}),t.calculateAspects=function(e,t,r=!0){const s=[];if(!t||t.length<2)return s;for(let a=0;a<t.length;a++)for(let o=a+1;o<t.length;o++){const u=n(e,t[a],t[o],r);u&&s.push(u)}return s},t.calculateMultichartAspects=function(e,t,r,s=!0){const a=[];if(!t||!r||0===t.length||0===r.length)return a;for(const o of t)for(const t of r){const r=n(e,o,t,s);r&&a.push(r)}return a}},156:function(e,t,n){var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var s=Object.getOwnPropertyDescriptor(t,n);s&&!("get"in s?!t.__esModule:s.writable||s.configurable)||(s={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,s)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),s=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||r(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),t.ChartSettings=t.ZODIAC_SIGNS=t.DEFAULT_ASPECT_CATEGORIES=t.DEFAULT_ASPECTS=t.DEFAULT_SETTINGS=t.chart2txt=void 0;var a=n(723);Object.defineProperty(t,"chart2txt",{enumerable:!0,get:function(){return a.formatChartToText}}),s(n(613),t);var o=n(921);Object.defineProperty(t,"DEFAULT_SETTINGS",{enumerable:!0,get:function(){return o.DEFAULT_SETTINGS}}),Object.defineProperty(t,"DEFAULT_ASPECTS",{enumerable:!0,get:function(){return o.DEFAULT_ASPECTS}}),Object.defineProperty(t,"DEFAULT_ASPECT_CATEGORIES",{enumerable:!0,get:function(){return o.DEFAULT_ASPECT_CATEGORIES}}),Object.defineProperty(t,"ZODIAC_SIGNS",{enumerable:!0,get:function(){return o.ZODIAC_SIGNS}});var u=n(230);Object.defineProperty(t,"ChartSettings",{enumerable:!0,get:function(){return u.ChartSettings}});const i=n(723);t.default=i.formatChartToText},172:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateChartHeaderOutput=function(e,t="CHART"){return[`[${t}: ${e||"Unknown"}]`]}},230:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ChartSettings=void 0;const r=n(921);t.ChartSettings=class{constructor(e={}){const t={...r.DEFAULT_SETTINGS,...e};this.includeSignDegree=t.includeSignDegree,this.includeAscendant=t.includeAscendant,this.houseSystemName=t.houseSystemName,this.includeHouseDegree=t.includeHouseDegree,this.aspectDefinitions=t.aspectDefinitions||r.DEFAULT_ASPECTS,this.aspectCategories=t.aspectCategories||r.DEFAULT_ASPECT_CATEGORIES,this.skipOutOfSignAspects=t.skipOutOfSignAspects,this.dateFormat=t.dateFormat}}},234:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generatePlanetsOutput=function(e,t,n){const s=["[PLANETS]"];e.forEach((e=>{const n=(0,r.getDegreeSign)(e.degree),a=Math.floor((0,r.getDegreeInSign)(e.degree)),o=void 0!==e.speed&&e.speed<0?" Rx":"";let u=`${e.name}: ${a}° ${n}${o}`;if(t&&12===t.length){const n=function(e,t){if(!t||12!==t.length)return 0;for(let n=0;n<12;n++){const r=t[n],s=t[(n+1)%12];if(r<s){if(e>=r&&e<s)return n+1}else if(e>=r||e<s)return n+1}return 0}(e.degree,t);n>0&&(u+=`, House ${n}`)}s.push(u)})),0===e.length&&s.push("No planets listed.");return s};const r=n(904)},388:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateMetadataOutput=function(e,t,n){const r=["[METADATA]",`chart_type: ${t}`];n&&r.push(`house_system: ${n}`);return r.push(`date_format: ${e.dateFormat}`),r}},613:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.isMultiChartData=function(e){return Array.isArray(e)}},723:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.formatChartToText=function(e,t={}){const n=new s.ChartSettings(t),u=n.houseSystemName,i=[];if(!(0,r.isMultiChartData)(e)){if("transit"===e.chartType)throw new Error("Single chart data must not be transit.");return i.push(...(0,o.generateMetadataOutput)(n,e.chartType||"natal",u)),i.push(""),i.push(...g(n,e)),i.join("\n").trimEnd()}const c=S(e);i.push(...(0,o.generateMetadataOutput)(n,c,u)),i.push("");const p=e.filter((({chartType:e})=>"transit"!==e)),h=e.find((({chartType:e})=>"transit"===e));for(const e of p)i.push(...g(n,e));for(let e=0;e<p.length;e++)for(let t=e+1;t<p.length;t++)i.push(...f(n,p[e],p[t]));if(h){i.push(...d(n,h));for(const e of p){const t=(0,a.calculateMultichartAspects)(n.aspectDefinitions,e.planets,h.planets,n.skipOutOfSignAspects);i.push(...(0,l.generateAspectsOutput)(`[TRANSIT ASPECTS: ${e.name}]`,t,n,e.name,h.name,!0)),i.push("")}}return i.join("\n").trimEnd()};const r=n(613),s=n(230),a=n(75),o=n(388),u=n(172),i=n(888),c=n(945),p=n(234),l=n(784),h=n(756),g=(e,t,n)=>{const r=[];r.push(...(0,u.generateChartHeaderOutput)(t.name,n)),r.push(...(0,i.generateBirthdataOutput)(t.location,t.timestamp,e)),r.push(...(0,c.generateAnglesOutput)(t.ascendant,t.midheaven)),r.push(...(0,p.generatePlanetsOutput)(t.planets,t.houseCusps,e));const s=(0,a.calculateAspects)(e.aspectDefinitions,t.planets,e.skipOutOfSignAspects);return r.push(...(0,l.generateAspectsOutput)("[ASPECTS]",s,e)),r.push(""),r},f=(e,t,n)=>{const r=[],s="event"===t.chartType&&"event"===n.chartType?"EVENT_RELATIONSHIP":"event"===t.chartType||"event"===n.chartType?"NATAL_EVENT":"SYNASTRY";r.push(...(0,u.generateChartHeaderOutput)(`${t.name}-${n.name}`,s));const o=(0,a.calculateMultichartAspects)(e.aspectDefinitions,t.planets,n.planets,e.skipOutOfSignAspects);return r.push(...(0,l.generateAspectsOutput)("[PLANET-PLANET ASPECTS]",o,e,t.name,n.name)),r.push(""),r.push(...(0,h.generateHouseOverlaysOutput)(t,n,e)),r.push(""),r},d=(e,t)=>{const n=[];return n.push(...(0,u.generateChartHeaderOutput)(t.name,"TRANSIT")),n.push(...(0,i.generateBirthdataOutput)(t.location,t.timestamp,e,"[DATETIME]")),n.push(...(0,p.generatePlanetsOutput)(t.planets,t.houseCusps,e)),n.push(""),n},S=e=>{let t="natal",n="";const r=e.filter((({chartType:e})=>"transit"!==e&&"event"!==e)),s=e.filter((({chartType:e})=>"event"===e)),a=e.filter((({chartType:e})=>"transit"===e));if(a.length>1)throw new Error("Must provide at most one transit chart");const o=a.length>0;if(r.length>0?0===s.length?o&&(n="_with_transit"):n=1===s.length?o?"_with_event_and_transit":"_with_event":o?"_with_events_and_transit":"_with_events":o&&(n="_with_transit"),0===r.length){if(0===s.length)throw new Error("Must provide at least one non-transit chart");t=1===s.length?"event":"multi_event"}else t=1===r.length?"natal":2===r.length?"synastry":"group_synastry";return t+n}},756:(e,t)=>{function n(e,t){if(!t||12!==t.length)return 0;for(let n=0;n<12;n++){const r=t[n],s=t[(n+1)%12];if(r<s){if(e>=r&&e<s)return n+1}else if(e>=r||e<s)return n+1}return 0}Object.defineProperty(t,"__esModule",{value:!0}),t.generateHouseOverlaysOutput=function(e,t,r){const s=["[HOUSE OVERLAYS]"],a=e.name,o=t.name;t.houseCusps&&12===t.houseCusps.length?(s.push(`${a}'s planets in ${o}'s houses:`),e.planets&&e.planets.length>0?e.planets.forEach((e=>{const r=n(e.degree,t.houseCusps);r>0?s.push(`${e.name}: House ${r}`):s.push(`${e.name}: (Could not determine house in ${o})`)})):s.push("(No planets listed for overlay)")):s.push(`${a}'s planets in ${o}'s houses: (${o} house cusps not available)`);s.push(""),e.houseCusps&&12===e.houseCusps.length?(s.push(`${o}'s planets in ${a}'s houses:`),t.planets&&t.planets.length>0?t.planets.forEach((t=>{const r=n(t.degree,e.houseCusps);r>0?s.push(`${t.name}: House ${r}`):s.push(`${t.name}: (Could not determine house in ${a})`)})):s.push("(No planets listed for overlay)")):s.push(`${o}'s planets in ${a}'s houses: (${a} house cusps not available)`);return s}},784:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateAspectsOutput=function(e,t,n,r,s,a=!1){const o=[e];let u=!1;n.aspectCategories.forEach((e=>{const n=t.filter((t=>{const n=t.orb,r=void 0===e.minOrb||n>e.minOrb,s=n<=e.maxOrb;return r&&s}));if(n.length>0){u=!0;let t=`orb < ${e.maxOrb.toFixed(1)}°`;void 0!==e.minOrb&&(t=e.minOrb<e.maxOrb?`orb ${e.minOrb.toFixed(1)}-${e.maxOrb.toFixed(1)}°`:`orb > ${e.minOrb.toFixed(1)}° & < ${e.maxOrb.toFixed(1)}°`),o.push(`[${e.name.toUpperCase()}: ${t}]`),n.sort(((e,t)=>e.orb-t.orb)),n.forEach((e=>{const t=r?`${r}'s ${e.planetA}`:e.planetA;let n=e.planetB;a?n=`transiting ${e.planetB}`:s&&(n=`${s}'s ${e.planetB}`),o.push(`${t} ${e.aspectType} ${n}: ${e.orb.toFixed(1)}°`)}))}})),!u&&t.length>0?o.push("No aspects within defined categories."):0===t.length&&o.push("None");return o}},888:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateBirthdataOutput=function(e,t,n,s="[BIRTHDATA]"){if(!t)return[`${s} Not available`];const a=(0,r.formatDateCustom)(t,n.dateFormat),o=(0,r.formatTime)(t);return[`${s} ${e||"Unknown Location"}, ${a}, ${o}`]};const r=n(889)},889:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.formatDateCustom=function(e,t){const n=e.getMonth()+1,r=e.getDate(),s=e.getFullYear();switch(t.toUpperCase()){case"MM/DD/YYYY":return`${n.toString().padStart(2,"0")}/${r.toString().padStart(2,"0")}/${s}`;case"DD/MM/YYYY":return`${r.toString().padStart(2,"0")}/${n.toString().padStart(2,"0")}/${s}`;case"YYYY-MM-DD":return`${s}-${n.toString().padStart(2,"0")}-${r.toString().padStart(2,"0")}`;default:return console.warn(`Unrecognized date format: ${t}. Falling back to toLocaleDateString().`),e.toLocaleDateString()}},t.formatTime=function(e){return e.toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!0})}},904:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.getDegreeSign=function(e){const t=Math.floor(e/30)%12;if(t<0||t>=r.ZODIAC_SIGNS.length)return console.error(`Invalid sign index computed: ${t} for degree ${e}`),"Unknown Sign";return r.ZODIAC_SIGNS[t]},t.getDegreeInSign=function(e){return e%30};const r=n(921)},921:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DEFAULT_SETTINGS=t.DEFAULT_ASPECT_CATEGORIES=t.DEFAULT_ASPECTS=t.ZODIAC_SIGNS=void 0,t.ZODIAC_SIGNS=["Aries","Taurus","Gemini","Cancer","Leo","Virgo","Libra","Scorpio","Sagittarius","Capricorn","Aquarius","Pisces"],t.DEFAULT_ASPECTS=[{name:"conjunction",angle:0,orb:5},{name:"opposition",angle:180,orb:5},{name:"trine",angle:120,orb:5},{name:"square",angle:90,orb:5},{name:"sextile",angle:60,orb:3}],t.DEFAULT_ASPECT_CATEGORIES=[{name:"MAJOR",maxOrb:2},{name:"MODERATE",minOrb:2,maxOrb:4}],t.DEFAULT_SETTINGS={includeSignDegree:!0,houseSystemName:"whole_sign",includeHouseDegree:!1,includeAscendant:!0,aspectDefinitions:t.DEFAULT_ASPECTS,aspectCategories:t.DEFAULT_ASPECT_CATEGORIES,skipOutOfSignAspects:!0,dateFormat:"MM/DD/YYYY"}},945:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateAnglesOutput=function(e,t){const n=["[ANGLES]"];void 0!==e?n.push(`ASC: ${Math.floor((0,r.getDegreeInSign)(e))}° ${(0,r.getDegreeSign)(e)}`):n.push("ASC: Not available");void 0!==t?n.push(`MC: ${Math.floor((0,r.getDegreeInSign)(t))}° ${(0,r.getDegreeSign)(t)}`):n.push("MC: Not available");return n};const r=n(904)}},t={};var n=function n(r){var s=t[r];if(void 0!==s)return s.exports;var a=t[r]={exports:{}};return e[r].call(a.exports,a,a.exports,n),a.exports}(156);return n=n.default})()));
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.chart2txt=t():e.chart2txt=t()}(this,(()=>(()=>{"use strict";var e={75:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.calculateAspects=function(e,t,n=!0){const r=[];if(!t||t.length<2)return r;for(let a=0;a<t.length;a++)for(let s=a+1;s<t.length;s++){const i=o(e,t[a],t[s],n);i&&r.push(i)}return r},t.calculateMultichartAspects=function(e,t,n,r=!0){const a=[];if(!t||!n||0===t.length||0===n.length)return a;for(const s of t)for(const t of n){const n=o(e,s,t,r);n&&a.push(n)}return a};const r=n(904),a=n(318);function s(e){const t=e<=180?e:360-e;switch(t){case 0:return 0;case 30:return 1;case 60:return 2;case 90:return 3;case 120:return 4;case 150:return 5;case 180:return 6;default:return Math.round(t/30)}}function i(e,t,n){if(void 0===e.speed||void 0===t.speed)return"exact";const s=e.speed,i=t.speed,o=(0,r.normalizeDegree)(e.degree),u=(0,r.normalizeDegree)(t.degree);let l=Math.abs(o-u);l>180&&(l=360-l);const c=Math.abs(l-n);if((0,a.isExactAspect)(c))return"exact";if(0===s-i)return"exact";const p=(0,r.normalizeDegree)(o+.1*s),h=(0,r.normalizeDegree)(u+.1*i),d=Math.abs(l-n);let f=Math.abs(p-h);f>180&&(f=360-f);return Math.abs(f-n)<d?"applying":"separating"}function o(e,t,n,o){const u=(0,a.roundDegrees)((0,r.normalizeDegree)(t.degree)),l=(0,a.roundDegrees)((0,r.normalizeDegree)(n.degree));let c=Math.abs(u-l);c>180&&(c=360-c);let p=null;for(const r of e){const e=(0,a.roundDegrees)(Math.abs(c-r.angle));if(o){const e=Math.floor(u/30),t=Math.floor(l/30),n=s(r.angle);let a=Math.abs(e-t);if(a>6&&(a=12-a),a!==n)continue}if(e<=r.orb&&(!p||e<p.orb)){const a=i(t,n,r.angle);p={planetA:t.name,planetB:n.name,aspectType:r.name,orb:e,application:a}}}return p}},82:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateDispositorsOutput=function(e){const t=["[DISPOSITOR TREE]"];if(0===e.length)return t.push("No planets available for dispositor analysis."),t;const n=(0,r.analyzeDispositors)(e),a=(0,r.formatDispositorAnalysis)(n);return t.push(...a),t};const r=n(729)},109:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateElementDistributionOutput=function(e,t,n){const a=[t?`[ELEMENT DISTRIBUTION: ${t}]`:"[ELEMENT DISTRIBUTION]"];if(0===e.length)return a.push("No planets available for element analysis."),a;const s=(0,r.analyzeSignDistributions)(e,n),i=(0,r.formatElementDistribution)(s.elements);return a.push(...i),a},t.generateModalityDistributionOutput=function(e,t,n){const a=[t?`[MODALITY DISTRIBUTION: ${t}]`:"[MODALITY DISTRIBUTION]"];if(0===e.length)return a.push("No planets available for modality analysis."),a;const s=(0,r.analyzeSignDistributions)(e,n),i=(0,r.formatModalityDistribution)(s.modalities);return a.push(...i),a},t.generatePolarityOutput=function(e,t,n){const a=[t?`[POLARITY: ${t}]`:"[POLARITY]"];if(0===e.length)return a.push("No planets available for polarity analysis."),a;const s=(0,r.analyzeSignDistributions)(e,n),i=(0,r.formatPolarityDistribution)(s.polarities);return a.push(...i),a};const r=n(858)},156:function(e,t,n){var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var a=Object.getOwnPropertyDescriptor(t,n);a&&!("get"in a?!t.__esModule:a.writable||a.configurable)||(a={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,a)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),a=this&&this.__exportStar||function(e,t){for(var n in e)"default"===n||Object.prototype.hasOwnProperty.call(t,n)||r(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),t.ChartSettings=t.ZODIAC_SIGNS=t.DEFAULT_ASPECT_CATEGORIES=t.DEFAULT_ASPECTS=t.DEFAULT_SETTINGS=t.chart2txt=void 0;var s=n(723);Object.defineProperty(t,"chart2txt",{enumerable:!0,get:function(){return s.formatChartToText}}),a(n(613),t);var i=n(921);Object.defineProperty(t,"DEFAULT_SETTINGS",{enumerable:!0,get:function(){return i.DEFAULT_SETTINGS}}),Object.defineProperty(t,"DEFAULT_ASPECTS",{enumerable:!0,get:function(){return i.DEFAULT_ASPECTS}}),Object.defineProperty(t,"DEFAULT_ASPECT_CATEGORIES",{enumerable:!0,get:function(){return i.DEFAULT_ASPECT_CATEGORIES}}),Object.defineProperty(t,"ZODIAC_SIGNS",{enumerable:!0,get:function(){return i.ZODIAC_SIGNS}});var o=n(230);Object.defineProperty(t,"ChartSettings",{enumerable:!0,get:function(){return o.ChartSettings}});const u=n(723);t.default=u.formatChartToText},172:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateChartHeaderOutput=function(e,t="CHART"){return[`[${t}: ${e||"Unknown"}]`]}},175:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.getOrdinal=function(e){const t=["th","st","nd","rd"],n=e%100;return e+(t[(n-20)%10]||t[n]||t[0])}},230:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ChartSettings=void 0;const r=n(921);t.ChartSettings=class{constructor(e={}){const t={...r.DEFAULT_SETTINGS,...e};this.includeSignDegree=t.includeSignDegree,this.includeAscendant=t.includeAscendant,this.houseSystemName=t.houseSystemName,this.includeHouseDegree=t.includeHouseDegree,this.aspectDefinitions=t.aspectDefinitions||r.DEFAULT_ASPECTS,this.aspectCategories=t.aspectCategories||r.DEFAULT_ASPECT_CATEGORIES,this.skipOutOfSignAspects=t.skipOutOfSignAspects,this.includeAspectPatterns=t.includeAspectPatterns,this.dateFormat=t.dateFormat}}},234:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generatePlanetsOutput=function(e,t,n){const o=["[PLANETS]"];e.forEach((e=>{const n=(0,r.getDegreeSign)(e.degree),u=Math.floor((0,r.getDegreeInSign)(e.degree)),l=void 0!==e.speed&&e.speed<0?" Retrograde":"",c=(0,a.formatPlanetWithDignities)(e,t);let p=`${e.name}: ${u}° ${n}${l}`;if(c&&(p+=` ${c}`),t&&12===t.length){const n=(0,i.getHouseForPoint)(e.degree,t);n&&(p+=`, ${(0,s.getOrdinal)(n)} house`)}o.push(p)})),0===e.length&&o.push("No planets listed.");return o};const r=n(904),a=n(400),s=n(175),i=n(600)},318:(e,t)=>{function n(e,n,r=t.DEFAULT_EPSILON){return Math.abs(e-n)<r}function r(e,n=t.DEFAULT_EPSILON){return Math.abs(e)<n}function a(e,r,a=t.DEFAULT_EPSILON){return n(e,r,a)}Object.defineProperty(t,"__esModule",{value:!0}),t.DEFAULT_EPSILON=void 0,t.floatEquals=n,t.isNearZero=r,t.roundDegrees=function(e){return Math.round(1e4*e)/1e4},t.degreeEquals=a,t.isOnCusp=function(e,t,n=.001){return a(e,t,n)},t.isExactAspect=function(e,t=.1){return r(e,t)},t.DEFAULT_EPSILON=1e-4},371:(e,t)=>{function n(e){return e&&"object"==typeof e?"string"!=typeof e.name||""===e.name.trim()?"Point name must be a non-empty string":"number"==typeof e.degree&&isFinite(e.degree)?void 0===e.speed||"number"==typeof e.speed&&isFinite(e.speed)?null:`Point ${e.name} has invalid speed value: ${e.speed}`:`Point ${e.name} has invalid degree value: ${e.degree}`:"Point must be an object"}function r(e){if(!Array.isArray(e))return"Points must be an array";for(let t=0;t<e.length;t++){const r=n(e[t]);if(r)return`Point at index ${t}: ${r}`}const t=e.map((e=>e.name)),r=t.filter(((e,n)=>t.indexOf(e)!==n));return r.length>0?`Duplicate point names found: ${r.join(", ")}`:null}function a(e){if(void 0===e)return null;if(!Array.isArray(e))return"House cusps must be an array";if(12!==e.length)return`House cusps must contain exactly 12 values, got ${e.length}`;for(let t=0;t<e.length;t++)if("number"!=typeof e[t]||!isFinite(e[t]))return`House cusp ${t+1} has invalid value: ${e[t]}`;return null}function s(e){if(!e||"object"!=typeof e)return"Chart data must be an object";if("string"!=typeof e.name||""===e.name.trim())return"Chart name must be a non-empty string";const t=r(e.planets);if(t)return`Planets validation failed: ${t}`;if(void 0!==e.ascendant&&("number"!=typeof e.ascendant||!isFinite(e.ascendant)))return`Ascendant has invalid value: ${e.ascendant}`;if(void 0!==e.midheaven&&("number"!=typeof e.midheaven||!isFinite(e.midheaven)))return`Midheaven has invalid value: ${e.midheaven}`;const n=a(e.houseCusps);if(n)return`House cusps validation failed: ${n}`;if(void 0!==e.points){const t=r(e.points);if(t)return`Additional points validation failed: ${t}`}if(void 0!==e.timestamp&&(!(e.timestamp instanceof Date)||isNaN(e.timestamp.getTime())))return"Timestamp must be a valid Date object";if(void 0!==e.location&&"string"!=typeof e.location)return"Location must be a string";if(void 0!==e.chartType){const t=["natal","event","transit"];if(!t.includes(e.chartType))return`Chart type must be one of: ${t.join(", ")}`}return null}function i(e){if(!Array.isArray(e))return"Multi-chart data must be an array";if(0===e.length)return"Multi-chart data must contain at least one chart";if(e.length>10)return"Multi-chart data cannot contain more than 10 charts";for(let t=0;t<e.length;t++){const n=s(e[t]);if(n)return`Chart at index ${t} (${e[t]?.name||"unnamed"}): ${n}`}const t=e.map((e=>e.name)),n=t.filter(((e,n)=>t.indexOf(e)!==n));if(n.length>0)return`Duplicate chart names found: ${n.join(", ")}`;return e.filter((e=>"transit"===e.chartType)).length>1?"Cannot have more than one transit chart":null}Object.defineProperty(t,"__esModule",{value:!0}),t.validatePoint=n,t.validatePoints=r,t.validateHouseCusps=a,t.validateChartData=s,t.validateMultiChartData=i,t.validateInputData=function(e){if(!e)return"Data is required";return Array.isArray(e)?i(e):s(e)}},388:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateMetadataOutput=function(e,t,n){const r=["[METADATA]",`chart_type: ${t}`];n&&r.push(`house_system: ${n}`);return r.push(`date_format: ${e.dateFormat}`),r}},400:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.getPlanetDignities=s,t.getSignRulers=i,t.formatPlanetWithDignities=function(e,t){const n=(0,r.getDegreeSign)(e.degree),a=s(e.name,n),o=i(n);let u="";a.length>0&&a.includes("Domicile")?u=`[${a.join(", ")}]`:a.length>0&&o.length>0?u=`[${a.join(", ")} | Ruler: ${o.join(", ")}]`:o.length>0&&(u=`[Ruler: ${o.join(", ")}]`);return u};const r=n(904),a={Aries:{rulers:["Mars"],exaltation:"Sun",detriment:"Venus",fall:"Saturn"},Taurus:{rulers:["Venus"],exaltation:"Moon",detriment:"Mars",fall:"Uranus"},Gemini:{rulers:["Mercury"],detriment:"Jupiter"},Cancer:{rulers:["Moon"],exaltation:"Jupiter",detriment:"Saturn",fall:"Mars"},Leo:{rulers:["Sun"],detriment:"Saturn",fall:"Neptune"},Virgo:{rulers:["Mercury"],exaltation:"Mercury",detriment:"Jupiter",fall:"Venus"},Libra:{rulers:["Venus"],exaltation:"Saturn",detriment:"Mars",fall:"Sun"},Scorpio:{rulers:["Mars"],detriment:"Venus",fall:"Moon"},Sagittarius:{rulers:["Jupiter"],detriment:"Mercury"},Capricorn:{rulers:["Saturn"],exaltation:"Mars",detriment:"Moon",fall:"Jupiter"},Aquarius:{rulers:["Saturn"],detriment:"Sun",fall:"Neptune"},Pisces:{rulers:["Jupiter"],exaltation:"Venus",detriment:"Mercury",fall:"Mercury"}};function s(e,t){const n=[],r=t.trim(),s=a[r];return s?(s.rulers.includes(e)&&n.push("Domicile"),s.exaltation===e&&n.push("Exaltation"),s.detriment===e&&n.push("Detriment"),s.fall&&s.fall===e&&n.push("Fall"),n):n}function i(e){const t=e.trim(),n=a[t];return n?n.rulers:[]}},600:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.validateHouseCusps=s,t.getHouseForPoint=function(e,t){if(!s(t))return null;if(!isFinite(e))return null;const n=(0,a.roundDegrees)((0,r.normalizeDegree)(e)),i=t.map((e=>(0,a.roundDegrees)((0,r.normalizeDegree)(e))));for(let e=0;e<12;e++)if((0,a.isOnCusp)(n,i[e]))return e+1;for(let e=0;e<12;e++){const t=i[e],r=i[(e+1)%12];if(t<r){if(n>t&&n<r)return e+1}else if(n>t||n<r)return e+1}return console.warn(`Point at ${n}° does not fall in any house`),null};const r=n(904),a=n(318);function s(e){if(!e||12!==e.length)return!1;for(const t of e)if(!isFinite(t))return!1;return!0}},613:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.isMultiChartData=function(e){return Array.isArray(e)}},668:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateHousesOutput=function(e){const t=["[HOUSE CUSPS]"];if(!e||12!==e.length)return t.push("House cusps not available"),t;for(let n=0;n<6;n++){const s=n,i=n+6,o=e[s],u=e[i],l=(0,r.getDegreeSign)(o),c=Math.floor((0,r.getDegreeInSign)(o)),p=(0,a.getOrdinal)(s+1)+" house",h=(0,r.getDegreeSign)(u),d=Math.floor((0,r.getDegreeInSign)(u)),f=(0,a.getOrdinal)(i+1)+" house",g=`${p}: ${c}° ${l}`.padEnd(24),m=`${f}: ${d}° ${h}`;t.push(`${g} ${m}`)}return t};const r=n(904),a=n(175)},723:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.formatChartToText=function(e,t={}){const n=(0,s.validateInputData)(e);if(n)throw new Error(`Invalid chart data: ${n}`);const o=new a.ChartSettings(t),c=o.houseSystemName,p=[];if(!(0,r.isMultiChartData)(e)){if("transit"===e.chartType)throw new Error("Single chart data must not be transit.");return p.push(...(0,l.generateMetadataOutput)(o,e.chartType||"natal",c)),p.push(""),p.push(...A(o,e)),p.join("\n").trimEnd()}const h=$(e);p.push(...(0,l.generateMetadataOutput)(o,h,c)),p.push("");const d=e.filter((({chartType:e})=>"transit"!==e)),f=e.find((({chartType:e})=>"transit"===e));for(const e of d)p.push(...A(o,e));for(let e=0;e<d.length;e++)for(let t=e+1;t<d.length;t++)p.push(...v(o,d[e],d[t]));if(f){p.push(...y(o,f));for(const e of d){const t=(0,i.calculateMultichartAspects)(o.aspectDefinitions,u(e),u(f),o.skipOutOfSignAspects);p.push(...(0,m.generateAspectsOutput)(`[TRANSIT ASPECTS: ${e.name}]`,t,o,e.name,f.name,!0)),p.push("")}}return p.join("\n").trimEnd()};const r=n(613),a=n(230),s=n(371),i=n(75),o=n(919);function u(e){const t=[...e.planets];return void 0!==e.ascendant&&t.push({name:"Ascendant",degree:e.ascendant}),void 0!==e.midheaven&&t.push({name:"Midheaven",degree:e.midheaven}),t}const l=n(388),c=n(172),p=n(888),h=n(945),d=n(668),f=n(234),g=n(82),m=n(784),S=n(762),b=n(756),O=n(109),A=(e,t,n)=>{const r=[];r.push(...(0,c.generateChartHeaderOutput)(t.name,n)),r.push(...(0,p.generateBirthdataOutput)(t.location,t.timestamp,e)),r.push(...(0,h.generateAnglesOutput)(t.ascendant,t.midheaven)),r.push(...(0,d.generateHousesOutput)(t.houseCusps)),r.push(...(0,f.generatePlanetsOutput)(t.planets,t.houseCusps,e)),r.push(...(0,g.generateDispositorsOutput)(t.planets)),r.push(...(0,O.generateElementDistributionOutput)(t.planets,void 0,t.ascendant)),r.push(...(0,O.generateModalityDistributionOutput)(t.planets,void 0,t.ascendant)),r.push(...(0,O.generatePolarityOutput)(t.planets,void 0,t.ascendant));const a=(0,i.calculateAspects)(e.aspectDefinitions,u(t),e.skipOutOfSignAspects);if(r.push(...(0,m.generateAspectsOutput)("[ASPECTS]",a,e)),e.includeAspectPatterns){const e=(0,o.detectAspectPatterns)(t.planets,t.houseCusps);r.push(...(0,S.generateAspectPatternsOutput)(e))}return r.push(""),r},v=(e,t,n)=>{const r=[],a="event"===t.chartType&&"event"===n.chartType?"EVENT_RELATIONSHIP":"event"===t.chartType||"event"===n.chartType?"NATAL_EVENT":"SYNASTRY";r.push(...(0,c.generateChartHeaderOutput)(`${t.name}-${n.name}`,a));const s=(0,i.calculateMultichartAspects)(e.aspectDefinitions,u(t),u(n),e.skipOutOfSignAspects);return r.push(...(0,m.generateAspectsOutput)("[PLANET-PLANET ASPECTS]",s,e,t.name,n.name)),r.push(""),r.push(...(0,b.generateHouseOverlaysOutput)(t,n,e)),r.push(""),r},y=(e,t)=>{const n=[];return n.push(...(0,c.generateChartHeaderOutput)(t.name,"TRANSIT")),n.push(...(0,p.generateBirthdataOutput)(t.location,t.timestamp,e,"[DATETIME]")),n.push(...(0,f.generatePlanetsOutput)(t.planets,t.houseCusps,e)),n.push(""),n},$=e=>{let t="natal",n="";const r=e.filter((({chartType:e})=>"transit"!==e&&"event"!==e)),a=e.filter((({chartType:e})=>"event"===e)),s=e.filter((({chartType:e})=>"transit"===e));if(s.length>1)throw new Error("Must provide at most one transit chart");const i=s.length>0;if(r.length>0?0===a.length?i&&(n="_with_transit"):n=1===a.length?i?"_with_event_and_transit":"_with_event":i?"_with_events_and_transit":"_with_events":i&&(n="_with_transit"),0===r.length){if(0===a.length)throw new Error("Must provide at least one non-transit chart");t=1===a.length?"event":"multi_event"}else t=1===r.length?"natal":2===r.length?"synastry":"group_synastry";return t+n}},729:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.analyzeDispositors=function(e){const t=new Map,n=new Map;e.forEach((e=>{const s=(0,r.getDegreeSign)(e.degree),i=(0,a.getSignRulers)(s);t.set(e.name,i),i.forEach((t=>{n.has(t)||n.set(t,[]),n.get(t).push(e.name)}))}));const s=[],i=new Set(e.map((e=>e.name)));e.forEach((e=>{const n=t.get(e.name)||[],r=n.includes(e.name),a=n.length>0&&!n.some((e=>i.has(e)));(r||a)&&s.push(e.name)}));return{chains:e.map((e=>({planet:e.name,disposedBy:t.get(e.name)||[],disposes:n.get(e.name)||[]}))),finalDispositors:s}},t.formatDispositorAnalysis=function(e){const t=[];return e.chains.forEach((n=>{const r=s(n.planet,e.chains).join(" → ");t.push(`${n.planet} → ${r}`)})),t};const r=n(904),a=n(400);function s(e,t,n=[]){const r=t.find((t=>t.planet===e));if(!r||0===r.disposedBy.length)return["(final)"];const a=r.disposedBy.filter((e=>t.some((t=>t.planet===e))));if(0===a.length)return["(final)"];const i=a[0];if(i===e)return["(final)"];if(n.includes(i))return["(cycle)"];const o=[...n,e];return[i,...s(i,t,o)]}},756:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateHouseOverlaysOutput=function(e,t,n){const s=["[HOUSE OVERLAYS]"],i=e.name,o=t.name;t.houseCusps&&12===t.houseCusps.length?(s.push(`${i}'s planets in ${o}'s houses:`),e.planets&&e.planets.length>0?e.planets.forEach((e=>{const n=(0,a.getHouseForPoint)(e.degree,t.houseCusps);n?s.push(`- ${e.name}: ${(0,r.getOrdinal)(n)}`):s.push(`- ${e.name}: (Could not determine house in ${o})`)})):s.push("(No planets listed for overlay)")):s.push(`${i}'s planets in ${o}'s houses: (${o} house cusps not available)`);s.push(""),e.houseCusps&&12===e.houseCusps.length?(s.push(`${o}'s planets in ${i}'s houses:`),t.planets&&t.planets.length>0?t.planets.forEach((t=>{const n=(0,a.getHouseForPoint)(t.degree,e.houseCusps);n?s.push(`- ${t.name}: ${(0,r.getOrdinal)(n)}`):s.push(`- ${t.name}: (Could not determine house in ${i})`)})):s.push("(No planets listed for overlay)")):s.push(`${o}'s planets in ${i}'s houses: (${i} house cusps not available)`);return s};const r=n(175),a=n(600)},762:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateAspectPatternsOutput=function(e){const t=["[ASPECT PATTERNS]"];if(0===e.length)return t.push("No aspect patterns detected."),t;const n=["T-Square","Grand Trine","Grand Cross","Stellium","Yod","Mystic Rectangle","Kite"];e.sort(((e,t)=>n.indexOf(e.type)-n.indexOf(t.type))).forEach((e=>{switch(e.type){case"T-Square":t.push(...function(e){if("T-Square"!==e.type)return[];const t=["T-Square:"];return t.push(` - Apex: ${s(e.apex)}`),t.push(` - Opposition: ${s(e.opposition[0])} - ${s(e.opposition[1])}`),t.push(` - Mode: ${e.mode}`),t.push(` - Average orb: ${e.averageOrb.toFixed(1)}°`),t.push(""),t}(e));break;case"Grand Trine":t.push(...function(e){if("Grand Trine"!==e.type)return[];const t=["Grand Trine:"];return e.planets.forEach(((e,n)=>{t.push(` - Planet ${n+1}: ${s(e)}`)})),t.push(` - Element: ${e.element}`),t.push(` - Average orb: ${e.averageOrb.toFixed(1)}°`),t.push(""),t}(e));break;case"Stellium":t.push(...function(e){if("Stellium"!==e.type)return[];const t=["Stellium:"],n=e.planets.map((e=>e.name)).join(", ");t.push(` - Planets: ${n}`),e.sign&&t.push(` - Sign: ${e.sign}`);if(e.houses.length>0){const n=1===e.houses.length?`${(0,a.getOrdinal)(e.houses[0])}`:e.houses.map((e=>(0,a.getOrdinal)(e))).join("-");t.push(` - Houses: ${n}`)}return t.push(` - Span: ${e.span.toFixed(1)}°`),t.push(""),t}(e));break;case"Grand Cross":t.push(...function(e){if("Grand Cross"!==e.type)return[];const t=["Grand Cross:"];return e.planets.forEach(((e,n)=>{t.push(` - Planet ${n+1}: ${s(e)}`)})),t.push(` - Mode: ${e.mode}`),t.push(` - Average orb: ${e.averageOrb.toFixed(1)}°`),t.push(""),t}(e));break;case"Yod":t.push(...function(e){if("Yod"!==e.type)return[];const t=["Yod:"];return t.push(` - Apex: ${s(e.apex)}`),t.push(` - Base planet 1: ${s(e.base[0])}`),t.push(` - Base planet 2: ${s(e.base[1])}`),t.push(` - Average orb: ${e.averageOrb.toFixed(1)}°`),t.push(""),t}(e));break;case"Mystic Rectangle":t.push(...function(e){if("Mystic Rectangle"!==e.type)return[];const t=["Mystic Rectangle:"];return t.push(` - Opposition 1: ${s(e.oppositions[0][0])} - ${s(e.oppositions[0][1])}`),t.push(` - Opposition 2: ${s(e.oppositions[1][0])} - ${s(e.oppositions[1][1])}`),t.push(` - Average orb: ${e.averageOrb.toFixed(1)}°`),t.push(""),t}(e));break;case"Kite":t.push(...function(e){if("Kite"!==e.type)return[];const t=["Kite:"],n=e.grandTrine.map((e=>e.name)).join(", ");return t.push(` - Grand Trine planets: ${n}`),t.push(` - Opposition planet: ${s(e.opposition)}`),t.push(` - Average orb: ${e.averageOrb.toFixed(1)}°`),t.push(""),t}(e))}})),""===t[t.length-1]&&t.pop();return t};const r=n(904),a=n(175);function s(e){const t=Math.floor((0,r.getDegreeInSign)(e.degree)),n=e.house?` (${(0,a.getOrdinal)(e.house)} house)`:"";return`${e.name} ${t}° ${e.sign}${n}`}},784:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateAspectsOutput=function(e,t,n,r,a,s=!1){const i=[e];let o=!1;n.aspectCategories.forEach((e=>{const n=t.filter((t=>{const n=t.orb,r=void 0===e.minOrb||n>e.minOrb,a=n<=e.maxOrb;return r&&a}));if(n.length>0){o=!0;let t=`orb under ${e.maxOrb.toFixed(1)}°`;void 0!==e.minOrb&&(t=e.minOrb<e.maxOrb?`orb ${e.minOrb.toFixed(1)}-${e.maxOrb.toFixed(1)}°`:`orb over ${e.minOrb.toFixed(1)}° & under ${e.maxOrb.toFixed(1)}°`),i.push(`[${e.name}: ${t}]`),n.sort(((e,t)=>e.orb-t.orb)),n.forEach((e=>{const t=r?`${r}'s ${e.planetA}`:e.planetA;let n=e.planetB;s?n=`transiting ${e.planetB}`:a&&(n=`${a}'s ${e.planetB}`);const o=e.application&&"exact"!==e.application?` (${e.application})`:"";i.push(`${t} ${e.aspectType} ${n}: ${e.orb.toFixed(1)}°${o}`)}))}})),!o&&t.length>0?i.push("No aspects within defined categories."):0===t.length&&i.push("None");return i}},858:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.analyzeSignDistributions=function(e,t){const n={Fire:[],Earth:[],Air:[],Water:[]},o={Cardinal:0,Fixed:0,Mutable:0},u={Masculine:0,Feminine:0};if(e.forEach((e=>{const t=(0,r.getDegreeSign)(e.degree),l=a[t],c=s[t],p=i[t];l&&n[l].push(e.name),c&&o[c]++,p&&u[p]++})),void 0!==t){const e=(0,r.getDegreeSign)(t),l=a[e],c=s[e],p=i[e];l&&n[l].push("Ascendant"),c&&o[c]++,p&&u[p]++}return{elements:n,modalities:o,polarities:u}},t.formatElementDistribution=function(e){const t=[];return Object.entries(e).forEach((([e,n])=>{if(n.length>0){const r=n.join(", ");t.push(`${e}: ${n.length} (${r})`)}})),t},t.formatModalityDistribution=function(e){const t=[];return Object.entries(e).forEach((([e,n])=>{n>0&&t.push(`${e}: ${n}`)})),t},t.formatPolarityDistribution=function(e){const t=[];e.Masculine>0&&t.push(`Masculine (Active): ${e.Masculine}`);e.Feminine>0&&t.push(`Feminine (Receptive): ${e.Feminine}`);return t};const r=n(904),a={Aries:"Fire",Leo:"Fire",Sagittarius:"Fire",Taurus:"Earth",Virgo:"Earth",Capricorn:"Earth",Gemini:"Air",Libra:"Air",Aquarius:"Air",Cancer:"Water",Scorpio:"Water",Pisces:"Water"},s={Aries:"Cardinal",Cancer:"Cardinal",Libra:"Cardinal",Capricorn:"Cardinal",Taurus:"Fixed",Leo:"Fixed",Scorpio:"Fixed",Aquarius:"Fixed",Gemini:"Mutable",Virgo:"Mutable",Sagittarius:"Mutable",Pisces:"Mutable"},i={Aries:"Masculine",Gemini:"Masculine",Leo:"Masculine",Libra:"Masculine",Sagittarius:"Masculine",Aquarius:"Masculine",Taurus:"Feminine",Cancer:"Feminine",Virgo:"Feminine",Scorpio:"Feminine",Capricorn:"Feminine",Pisces:"Feminine"}},888:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateBirthdataOutput=function(e,t,n,a="[BIRTHDATA]"){if(!t)return[`${a} Not available`];const s=(0,r.formatDateCustom)(t,n.dateFormat),i=(0,r.formatTime)(t);return[`${a} ${e||"Unknown Location"} | ${s} | ${i}`]};const r=n(889)},889:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.formatDateCustom=function(e,t){const n=e.getMonth()+1,r=e.getDate(),a=e.getFullYear();switch(t.toUpperCase()){case"MM/DD/YYYY":return`${n.toString().padStart(2,"0")}/${r.toString().padStart(2,"0")}/${a}`;case"DD/MM/YYYY":return`${r.toString().padStart(2,"0")}/${n.toString().padStart(2,"0")}/${a}`;case"YYYY-MM-DD":return`${a}-${n.toString().padStart(2,"0")}-${r.toString().padStart(2,"0")}`;default:return console.warn(`Unrecognized date format: ${t}. Falling back to toLocaleDateString().`),e.toLocaleDateString()}},t.formatTime=function(e){return e.toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!0})}},904:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.normalizeDegree=a,t.getDegreeSign=function(e){const t=a(e),n=Math.floor(t/30);if(n<0||n>=r.ZODIAC_SIGNS.length)return console.error(`Invalid sign index computed: ${n} for normalized degree ${t}`),"Unknown Sign";return r.ZODIAC_SIGNS[n]},t.getDegreeInSign=function(e){return a(e)%30};const r=n(921);function a(e){if(!isFinite(e))throw new Error(`Invalid degree value: ${e}`);let t=e%360;return t<0&&(t+=360),t}},919:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.detectAspectPatterns=function(e,t){const n=[];return n.push(...function(e,t,n=8){const r=[];for(let a=0;a<e.length;a++)for(let l=a+1;l<e.length;l++)if(u(e[a],e[l],180,n))for(let c=0;c<e.length;c++)if(c!==a&&c!==l&&u(e[a],e[c],90,n)&&u(e[l],e[c],90,n)){const n=i(e[c],t),u=i(e[a],t),p=i(e[l],t),h=(s(e[a],e[l],180)+s(e[a],e[c],90)+s(e[l],e[c],90))/3,d=o(n.sign);r.push({type:"T-Square",apex:n,opposition:[u,p],mode:d,averageOrb:h})}return r}(e,t)),n.push(...l(e,t)),n.push(...function(e,t,n=3){const s=[],o=new Map;if(e.forEach((e=>{const t=(0,r.getDegreeSign)(e.degree);o.has(t)||o.set(t,[]),o.get(t).push(e)})),o.forEach(((e,r)=>{if(e.length>=n){const n=e.map((e=>i(e,t))),a=n.map((e=>e.house)).filter((e=>void 0!==e)),o=e.map((e=>e.degree)),u=Math.max(...o)-Math.min(...o);s.push({type:"Stellium",planets:n,sign:r,houses:[...new Set(a)].sort(),span:u})}})),t){const r=new Map;e.forEach((e=>{const n=(0,a.getHouseForPoint)(e.degree,t);n&&(r.has(n)||r.set(n,[]),r.get(n).push(e))})),r.forEach(((e,r)=>{if(e.length>=n){const n=e.map((e=>i(e,t))),a=e.map((e=>e.degree)),o=Math.max(...a)-Math.min(...a);s.find((e=>"Stellium"===e.type&&e.planets.some((e=>n.some((t=>t.name===e.name))))))||s.push({type:"Stellium",planets:n,houses:[r],span:o})}}))}return s}(e,t)),n.push(...function(e,t,n=8){const r=[];for(let a=0;a<e.length;a++)for(let l=a+1;l<e.length;l++)for(let c=l+1;c<e.length;c++)for(let p=c+1;p<e.length;p++){const h=[[a,l],[c,p]],d=[[a,c],[l,p],[a,p],[l,c]];let f=0,g=0;if(h.forEach((([t,r])=>{u(e[t],e[r],180,n)&&f++})),d.forEach((([t,r])=>{u(e[t],e[r],90,n)&&g++})),2===f&&4===g){const n=i(e[a],t),u=i(e[l],t),f=i(e[c],t),g=i(e[p],t);let m=0,S=0;h.forEach((([t,n])=>{m+=s(e[t],e[n],180),S++})),d.forEach((([t,n])=>{m+=s(e[t],e[n],90),S++}));const b=m/S,O=o(n.sign);r.push({type:"Grand Cross",planets:[n,u,f,g],mode:O,averageOrb:b})}}return r}(e,t)),n.push(...function(e,t,n=5){const r=[];for(let a=0;a<e.length;a++)for(let o=a+1;o<e.length;o++)if(u(e[a],e[o],60,n))for(let l=0;l<e.length;l++)if(l!==a&&l!==o&&u(e[a],e[l],150,n)&&u(e[o],e[l],150,n)){const n=i(e[l],t),u=i(e[a],t),c=i(e[o],t),p=(s(e[a],e[o],60)+s(e[a],e[l],150)+s(e[o],e[l],150))/3;r.push({type:"Yod",apex:n,base:[u,c],averageOrb:p})}return r}(e,t)),n.push(...function(e,t,n=8){const r=[];for(let a=0;a<e.length;a++)for(let o=a+1;o<e.length;o++)for(let l=o+1;l<e.length;l++)for(let c=l+1;c<e.length;c++){const p=[{oppositions:[[a,o],[l,c]],sextiles:[[a,l],[a,c],[o,l],[o,c]]},{oppositions:[[a,l],[o,c]],sextiles:[[a,o],[a,c],[l,o],[l,c]]},{oppositions:[[a,c],[o,l]],sextiles:[[a,o],[a,l],[c,o],[c,l]]}];for(const a of p){let o=0,l=0;if(a.oppositions.forEach((([t,r])=>{u(e[t],e[r],180,n)&&o++})),a.sextiles.forEach((([t,r])=>{(u(e[t],e[r],60,n)||u(e[t],e[r],120,n))&&l++})),2===o&&4===l){const n=i(e[a.oppositions[0][0]],t),o=i(e[a.oppositions[0][1]],t),u=i(e[a.oppositions[1][0]],t),l=i(e[a.oppositions[1][1]],t);let c=0,p=0;a.oppositions.forEach((([t,n])=>{c+=s(e[t],e[n],180),p++})),a.sextiles.forEach((([t,n])=>{const r=s(e[t],e[n],60),a=s(e[t],e[n],120);c+=Math.min(r,a),p++}));const h=c/p;r.push({type:"Mystic Rectangle",oppositions:[[n,o],[u,l]],averageOrb:h})}}}return r}(e,t)),n.push(...function(e,t,n=8){const r=[];return l(e,t,n).forEach((a=>{a.planets.forEach((o=>{e.forEach((l=>{if(!a.planets.some((e=>e.name===l.name))){const c=e.find((e=>e.name===o.name));if(c&&u(c,l,180,n)){const e=i(l,t),n=s(c,l,180),o=(a.averageOrb+n)/2;r.push({type:"Kite",grandTrine:a.planets,opposition:e,averageOrb:o})}}}))}))})),r}(e,t)),n};const r=n(904),a=n(600);function s(e,t,n){const a=(0,r.normalizeDegree)(e.degree),s=(0,r.normalizeDegree)(t.degree);let i=Math.abs(a-s);return i>180&&(i=360-i),Math.abs(i-n)}function i(e,t){const n=(0,r.getDegreeSign)(e.degree),s=t&&(0,a.getHouseForPoint)(e.degree,t)||void 0;return{name:e.name,degree:e.degree,sign:n,house:s}}function o(e){return["Aries","Cancer","Libra","Capricorn"].includes(e)?"Cardinal":["Taurus","Leo","Scorpio","Aquarius"].includes(e)?"Fixed":"Mutable"}function u(e,t,n,r){return s(e,t,n)<=r}function l(e,t,n=8){const r=[];for(let o=0;o<e.length;o++)for(let l=o+1;l<e.length;l++)for(let c=l+1;c<e.length;c++)if(u(e[o],e[l],120,n)&&u(e[l],e[c],120,n)&&u(e[c],e[o],120,n)){const n=i(e[o],t),u=i(e[l],t),p=i(e[c],t),h=(s(e[o],e[l],120)+s(e[l],e[c],120)+s(e[c],e[o],120))/3,d=(a=n.sign,["Aries","Leo","Sagittarius"].includes(a)?"Fire":["Taurus","Virgo","Capricorn"].includes(a)?"Earth":["Gemini","Libra","Aquarius"].includes(a)?"Air":"Water");r.push({type:"Grand Trine",planets:[n,u,p],element:d,averageOrb:h})}var a;return r}},921:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DEFAULT_SETTINGS=t.DEFAULT_ASPECT_CATEGORIES=t.DEFAULT_ASPECTS=t.ZODIAC_SIGNS=void 0,t.ZODIAC_SIGNS=["Aries","Taurus","Gemini","Cancer","Leo","Virgo","Libra","Scorpio","Sagittarius","Capricorn","Aquarius","Pisces"],t.DEFAULT_ASPECTS=[{name:"conjunction",angle:0,orb:5},{name:"opposition",angle:180,orb:5},{name:"trine",angle:120,orb:5},{name:"square",angle:90,orb:5},{name:"sextile",angle:60,orb:3}],t.DEFAULT_ASPECT_CATEGORIES=[{name:"TIGHT ASPECTS",maxOrb:2},{name:"MODERATE ASPECTS",minOrb:2,maxOrb:4}],t.DEFAULT_SETTINGS={includeSignDegree:!0,houseSystemName:"whole_sign",includeHouseDegree:!1,includeAscendant:!0,aspectDefinitions:t.DEFAULT_ASPECTS,aspectCategories:t.DEFAULT_ASPECT_CATEGORIES,skipOutOfSignAspects:!0,includeAspectPatterns:!1,dateFormat:"MM/DD/YYYY"}},945:(e,t,n)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.generateAnglesOutput=function(e,t){const n=["[ANGLES]"];void 0!==e?n.push(`Ascendant: ${Math.floor((0,r.getDegreeInSign)(e))}° ${(0,r.getDegreeSign)(e)}`):n.push("Ascendant: Not available");void 0!==t?n.push(`Midheaven: ${Math.floor((0,r.getDegreeInSign)(t))}° ${(0,r.getDegreeSign)(t)}`):n.push("Midheaven: Not available");return n};const r=n(904)}},t={};var n=function n(r){var a=t[r];if(void 0!==a)return a.exports;var s=t[r]={exports:{}};return e[r].call(s.exports,s,s.exports,n),s.exports}(156);return n=n.default})()));
@@ -7,6 +7,7 @@ export declare class ChartSettings implements Settings {
7
7
  skipOutOfSignAspects: boolean;
8
8
  aspectDefinitions: Aspect[];
9
9
  aspectCategories: AspectCategory[];
10
+ includeAspectPatterns: boolean;
10
11
  dateFormat: string;
11
12
  constructor(customSettings?: PartialSettings);
12
13
  }
@@ -14,6 +14,7 @@ class ChartSettings {
14
14
  this.aspectCategories =
15
15
  mergedSettings.aspectCategories || constants_1.DEFAULT_ASPECT_CATEGORIES; // Ensure array is not undefined
16
16
  this.skipOutOfSignAspects = mergedSettings.skipOutOfSignAspects;
17
+ this.includeAspectPatterns = mergedSettings.includeAspectPatterns;
17
18
  this.dateFormat = mergedSettings.dateFormat;
18
19
  }
19
20
  }
package/dist/constants.js CHANGED
@@ -23,8 +23,8 @@ exports.DEFAULT_ASPECTS = [
23
23
  { name: 'sextile', angle: 60, orb: 3 },
24
24
  ];
25
25
  exports.DEFAULT_ASPECT_CATEGORIES = [
26
- { name: 'MAJOR', maxOrb: 2 }, // Orb < 2°
27
- { name: 'MODERATE', minOrb: 2, maxOrb: 4 }, // Orb 2-4°
26
+ { name: 'TIGHT ASPECTS', maxOrb: 2 }, // Orb < 2°
27
+ { name: 'MODERATE ASPECTS', minOrb: 2, maxOrb: 4 }, // Orb 2-4°
28
28
  ];
29
29
  exports.DEFAULT_SETTINGS = {
30
30
  // sign settings
@@ -38,5 +38,7 @@ exports.DEFAULT_SETTINGS = {
38
38
  aspectDefinitions: exports.DEFAULT_ASPECTS,
39
39
  aspectCategories: exports.DEFAULT_ASPECT_CATEGORIES,
40
40
  skipOutOfSignAspects: true,
41
+ // pattern settings
42
+ includeAspectPatterns: false, // Aspect patterns disabled by default
41
43
  dateFormat: 'MM/DD/YYYY', // As per example output
42
44
  };
@@ -0,0 +1,5 @@
1
+ import { Point, AspectPattern } from '../types';
2
+ /**
3
+ * Main function to detect all aspect patterns
4
+ */
5
+ export declare function detectAspectPatterns(planets: Point[], houseCusps?: number[]): AspectPattern[];
@@ -0,0 +1,444 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectAspectPatterns = detectAspectPatterns;
4
+ const astrology_1 = require("./astrology");
5
+ const houseCalculations_1 = require("../utils/houseCalculations");
6
+ /**
7
+ * Helper function to calculate orb between two planets for a specific aspect angle
8
+ */
9
+ function calculateOrb(planet1, planet2, aspectAngle) {
10
+ const degree1 = (0, astrology_1.normalizeDegree)(planet1.degree);
11
+ const degree2 = (0, astrology_1.normalizeDegree)(planet2.degree);
12
+ let diff = Math.abs(degree1 - degree2);
13
+ if (diff > 180)
14
+ diff = 360 - diff;
15
+ return Math.abs(diff - aspectAngle);
16
+ }
17
+ /**
18
+ * Convert Point to PlanetPosition
19
+ */
20
+ function pointToPlanetPosition(point, houseCusps) {
21
+ const sign = (0, astrology_1.getDegreeSign)(point.degree);
22
+ const house = houseCusps
23
+ ? (0, houseCalculations_1.getHouseForPoint)(point.degree, houseCusps) || undefined
24
+ : undefined;
25
+ return {
26
+ name: point.name,
27
+ degree: point.degree,
28
+ sign,
29
+ house,
30
+ };
31
+ }
32
+ /**
33
+ * Determine the modality (Cardinal, Fixed, Mutable) of a sign
34
+ */
35
+ function getSignModality(sign) {
36
+ const cardinal = ['Aries', 'Cancer', 'Libra', 'Capricorn'];
37
+ const fixed = ['Taurus', 'Leo', 'Scorpio', 'Aquarius'];
38
+ const mutable = ['Gemini', 'Virgo', 'Sagittarius', 'Pisces'];
39
+ if (cardinal.includes(sign))
40
+ return 'Cardinal';
41
+ if (fixed.includes(sign))
42
+ return 'Fixed';
43
+ return 'Mutable';
44
+ }
45
+ /**
46
+ * Determine the element (Fire, Earth, Air, Water) of a sign
47
+ */
48
+ function getSignElement(sign) {
49
+ const fire = ['Aries', 'Leo', 'Sagittarius'];
50
+ const earth = ['Taurus', 'Virgo', 'Capricorn'];
51
+ const air = ['Gemini', 'Libra', 'Aquarius'];
52
+ const water = ['Cancer', 'Scorpio', 'Pisces'];
53
+ if (fire.includes(sign))
54
+ return 'Fire';
55
+ if (earth.includes(sign))
56
+ return 'Earth';
57
+ if (air.includes(sign))
58
+ return 'Air';
59
+ return 'Water';
60
+ }
61
+ /**
62
+ * Check if two planets form a specific aspect within orb
63
+ */
64
+ function hasAspect(planet1, planet2, aspectAngle, orb) {
65
+ const calculatedOrb = calculateOrb(planet1, planet2, aspectAngle);
66
+ return calculatedOrb <= orb;
67
+ }
68
+ /**
69
+ * Detect T-Square patterns
70
+ */
71
+ function detectTSquares(planets, houseCusps, maxOrb = 8) {
72
+ const patterns = [];
73
+ for (let i = 0; i < planets.length; i++) {
74
+ for (let j = i + 1; j < planets.length; j++) {
75
+ // Check for opposition
76
+ if (hasAspect(planets[i], planets[j], 180, maxOrb)) {
77
+ // Look for a third planet that squares both
78
+ for (let k = 0; k < planets.length; k++) {
79
+ if (k === i || k === j)
80
+ continue;
81
+ if (hasAspect(planets[i], planets[k], 90, maxOrb) &&
82
+ hasAspect(planets[j], planets[k], 90, maxOrb)) {
83
+ const apex = pointToPlanetPosition(planets[k], houseCusps);
84
+ const opp1 = pointToPlanetPosition(planets[i], houseCusps);
85
+ const opp2 = pointToPlanetPosition(planets[j], houseCusps);
86
+ const orb1 = calculateOrb(planets[i], planets[j], 180);
87
+ const orb2 = calculateOrb(planets[i], planets[k], 90);
88
+ const orb3 = calculateOrb(planets[j], planets[k], 90);
89
+ const averageOrb = (orb1 + orb2 + orb3) / 3;
90
+ // Determine modality from apex planet
91
+ const mode = getSignModality(apex.sign);
92
+ patterns.push({
93
+ type: 'T-Square',
94
+ apex,
95
+ opposition: [opp1, opp2],
96
+ mode,
97
+ averageOrb,
98
+ });
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ return patterns;
105
+ }
106
+ /**
107
+ * Detect Grand Trine patterns
108
+ */
109
+ function detectGrandTrines(planets, houseCusps, maxOrb = 8) {
110
+ const patterns = [];
111
+ for (let i = 0; i < planets.length; i++) {
112
+ for (let j = i + 1; j < planets.length; j++) {
113
+ for (let k = j + 1; k < planets.length; k++) {
114
+ // Check if all three planets form trines with each other
115
+ if (hasAspect(planets[i], planets[j], 120, maxOrb) &&
116
+ hasAspect(planets[j], planets[k], 120, maxOrb) &&
117
+ hasAspect(planets[k], planets[i], 120, maxOrb)) {
118
+ const planet1 = pointToPlanetPosition(planets[i], houseCusps);
119
+ const planet2 = pointToPlanetPosition(planets[j], houseCusps);
120
+ const planet3 = pointToPlanetPosition(planets[k], houseCusps);
121
+ const orb1 = calculateOrb(planets[i], planets[j], 120);
122
+ const orb2 = calculateOrb(planets[j], planets[k], 120);
123
+ const orb3 = calculateOrb(planets[k], planets[i], 120);
124
+ const averageOrb = (orb1 + orb2 + orb3) / 3;
125
+ // Determine element from the planets (should be same element for proper grand trine)
126
+ const element = getSignElement(planet1.sign);
127
+ patterns.push({
128
+ type: 'Grand Trine',
129
+ planets: [planet1, planet2, planet3],
130
+ element,
131
+ averageOrb,
132
+ });
133
+ }
134
+ }
135
+ }
136
+ }
137
+ return patterns;
138
+ }
139
+ /**
140
+ * Detect Stellium patterns (3+ planets in same sign or adjacent houses)
141
+ */
142
+ function detectStelliums(planets, houseCusps, minPlanets = 3) {
143
+ const patterns = [];
144
+ // Group by sign
145
+ const signGroups = new Map();
146
+ planets.forEach((planet) => {
147
+ const sign = (0, astrology_1.getDegreeSign)(planet.degree);
148
+ if (!signGroups.has(sign)) {
149
+ signGroups.set(sign, []);
150
+ }
151
+ signGroups.get(sign).push(planet);
152
+ });
153
+ // Check sign-based stelliums
154
+ signGroups.forEach((planetsInSign, sign) => {
155
+ if (planetsInSign.length >= minPlanets) {
156
+ const planetPositions = planetsInSign.map((p) => pointToPlanetPosition(p, houseCusps));
157
+ const houses = planetPositions
158
+ .map((p) => p.house)
159
+ .filter((h) => h !== undefined);
160
+ const degrees = planetsInSign.map((p) => p.degree);
161
+ const span = Math.max(...degrees) - Math.min(...degrees);
162
+ patterns.push({
163
+ type: 'Stellium',
164
+ planets: planetPositions,
165
+ sign,
166
+ houses: [...new Set(houses)].sort(),
167
+ span,
168
+ });
169
+ }
170
+ });
171
+ // Check house-based stelliums (if house cusps available)
172
+ if (houseCusps) {
173
+ const houseGroups = new Map();
174
+ planets.forEach((planet) => {
175
+ const house = (0, houseCalculations_1.getHouseForPoint)(planet.degree, houseCusps);
176
+ if (house) {
177
+ if (!houseGroups.has(house)) {
178
+ houseGroups.set(house, []);
179
+ }
180
+ houseGroups.get(house).push(planet);
181
+ }
182
+ });
183
+ houseGroups.forEach((planetsInHouse, house) => {
184
+ if (planetsInHouse.length >= minPlanets) {
185
+ const planetPositions = planetsInHouse.map((p) => pointToPlanetPosition(p, houseCusps));
186
+ const degrees = planetsInHouse.map((p) => p.degree);
187
+ const span = Math.max(...degrees) - Math.min(...degrees);
188
+ // Only add if not already covered by sign stellium
189
+ const existingSignStellium = patterns.find((p) => p.type === 'Stellium' &&
190
+ p.planets.some((planet) => planetPositions.some((pp) => pp.name === planet.name)));
191
+ if (!existingSignStellium) {
192
+ patterns.push({
193
+ type: 'Stellium',
194
+ planets: planetPositions,
195
+ houses: [house],
196
+ span,
197
+ });
198
+ }
199
+ }
200
+ });
201
+ }
202
+ return patterns;
203
+ }
204
+ /**
205
+ * Detect Grand Cross patterns
206
+ */
207
+ function detectGrandCrosses(planets, houseCusps, maxOrb = 8) {
208
+ const patterns = [];
209
+ for (let i = 0; i < planets.length; i++) {
210
+ for (let j = i + 1; j < planets.length; j++) {
211
+ for (let k = j + 1; k < planets.length; k++) {
212
+ for (let l = k + 1; l < planets.length; l++) {
213
+ // Check if planets form two oppositions and four squares
214
+ const pairs = [
215
+ [i, j],
216
+ [k, l],
217
+ ];
218
+ const otherPairs = [
219
+ [i, k],
220
+ [j, l],
221
+ [i, l],
222
+ [j, k],
223
+ ];
224
+ // Check for two oppositions
225
+ let oppositions = 0;
226
+ let squares = 0;
227
+ pairs.forEach(([a, b]) => {
228
+ if (hasAspect(planets[a], planets[b], 180, maxOrb)) {
229
+ oppositions++;
230
+ }
231
+ });
232
+ otherPairs.forEach(([a, b]) => {
233
+ if (hasAspect(planets[a], planets[b], 90, maxOrb)) {
234
+ squares++;
235
+ }
236
+ });
237
+ if (oppositions === 2 && squares === 4) {
238
+ const planet1 = pointToPlanetPosition(planets[i], houseCusps);
239
+ const planet2 = pointToPlanetPosition(planets[j], houseCusps);
240
+ const planet3 = pointToPlanetPosition(planets[k], houseCusps);
241
+ const planet4 = pointToPlanetPosition(planets[l], houseCusps);
242
+ // Calculate average orb
243
+ let totalOrb = 0;
244
+ let aspectCount = 0;
245
+ pairs.forEach(([a, b]) => {
246
+ totalOrb += calculateOrb(planets[a], planets[b], 180);
247
+ aspectCount++;
248
+ });
249
+ otherPairs.forEach(([a, b]) => {
250
+ totalOrb += calculateOrb(planets[a], planets[b], 90);
251
+ aspectCount++;
252
+ });
253
+ const averageOrb = totalOrb / aspectCount;
254
+ const mode = getSignModality(planet1.sign); // Determine from first planet
255
+ patterns.push({
256
+ type: 'Grand Cross',
257
+ planets: [planet1, planet2, planet3, planet4],
258
+ mode,
259
+ averageOrb,
260
+ });
261
+ }
262
+ }
263
+ }
264
+ }
265
+ }
266
+ return patterns;
267
+ }
268
+ /**
269
+ * Detect Yod patterns (two quincunxes to apex planet and one sextile between base planets)
270
+ */
271
+ function detectYods(planets, houseCusps, maxOrb = 5) {
272
+ const patterns = [];
273
+ for (let i = 0; i < planets.length; i++) {
274
+ for (let j = i + 1; j < planets.length; j++) {
275
+ // Check for sextile between base planets
276
+ if (hasAspect(planets[i], planets[j], 60, maxOrb)) {
277
+ // Look for apex planet that forms quincunxes with both
278
+ for (let k = 0; k < planets.length; k++) {
279
+ if (k === i || k === j)
280
+ continue;
281
+ if (hasAspect(planets[i], planets[k], 150, maxOrb) &&
282
+ hasAspect(planets[j], planets[k], 150, maxOrb)) {
283
+ const apex = pointToPlanetPosition(planets[k], houseCusps);
284
+ const base1 = pointToPlanetPosition(planets[i], houseCusps);
285
+ const base2 = pointToPlanetPosition(planets[j], houseCusps);
286
+ const orb1 = calculateOrb(planets[i], planets[j], 60);
287
+ const orb2 = calculateOrb(planets[i], planets[k], 150);
288
+ const orb3 = calculateOrb(planets[j], planets[k], 150);
289
+ const averageOrb = (orb1 + orb2 + orb3) / 3;
290
+ patterns.push({
291
+ type: 'Yod',
292
+ apex,
293
+ base: [base1, base2],
294
+ averageOrb,
295
+ });
296
+ }
297
+ }
298
+ }
299
+ }
300
+ }
301
+ return patterns;
302
+ }
303
+ /**
304
+ * Detect Mystic Rectangle patterns (two oppositions with sextiles and trines)
305
+ */
306
+ function detectMysticRectangles(planets, houseCusps, maxOrb = 8) {
307
+ const patterns = [];
308
+ for (let i = 0; i < planets.length; i++) {
309
+ for (let j = i + 1; j < planets.length; j++) {
310
+ for (let k = j + 1; k < planets.length; k++) {
311
+ for (let l = k + 1; l < planets.length; l++) {
312
+ // Check for two oppositions and appropriate sextiles/trines
313
+ const combinations = [
314
+ {
315
+ oppositions: [
316
+ [i, j],
317
+ [k, l],
318
+ ],
319
+ sextiles: [
320
+ [i, k],
321
+ [i, l],
322
+ [j, k],
323
+ [j, l],
324
+ ],
325
+ },
326
+ {
327
+ oppositions: [
328
+ [i, k],
329
+ [j, l],
330
+ ],
331
+ sextiles: [
332
+ [i, j],
333
+ [i, l],
334
+ [k, j],
335
+ [k, l],
336
+ ],
337
+ },
338
+ {
339
+ oppositions: [
340
+ [i, l],
341
+ [j, k],
342
+ ],
343
+ sextiles: [
344
+ [i, j],
345
+ [i, k],
346
+ [l, j],
347
+ [l, k],
348
+ ],
349
+ },
350
+ ];
351
+ for (const combo of combinations) {
352
+ let validOppositions = 0;
353
+ let validSextiles = 0;
354
+ combo.oppositions.forEach(([a, b]) => {
355
+ if (hasAspect(planets[a], planets[b], 180, maxOrb)) {
356
+ validOppositions++;
357
+ }
358
+ });
359
+ combo.sextiles.forEach(([a, b]) => {
360
+ if (hasAspect(planets[a], planets[b], 60, maxOrb) ||
361
+ hasAspect(planets[a], planets[b], 120, maxOrb)) {
362
+ validSextiles++;
363
+ }
364
+ });
365
+ if (validOppositions === 2 && validSextiles === 4) {
366
+ const pos1 = pointToPlanetPosition(planets[combo.oppositions[0][0]], houseCusps);
367
+ const pos2 = pointToPlanetPosition(planets[combo.oppositions[0][1]], houseCusps);
368
+ const pos3 = pointToPlanetPosition(planets[combo.oppositions[1][0]], houseCusps);
369
+ const pos4 = pointToPlanetPosition(planets[combo.oppositions[1][1]], houseCusps);
370
+ // Calculate average orb
371
+ let totalOrb = 0;
372
+ let aspectCount = 0;
373
+ combo.oppositions.forEach(([a, b]) => {
374
+ totalOrb += calculateOrb(planets[a], planets[b], 180);
375
+ aspectCount++;
376
+ });
377
+ combo.sextiles.forEach(([a, b]) => {
378
+ const sextileOrb = calculateOrb(planets[a], planets[b], 60);
379
+ const trineOrb = calculateOrb(planets[a], planets[b], 120);
380
+ totalOrb += Math.min(sextileOrb, trineOrb);
381
+ aspectCount++;
382
+ });
383
+ const averageOrb = totalOrb / aspectCount;
384
+ patterns.push({
385
+ type: 'Mystic Rectangle',
386
+ oppositions: [
387
+ [pos1, pos2],
388
+ [pos3, pos4],
389
+ ],
390
+ averageOrb,
391
+ });
392
+ }
393
+ }
394
+ }
395
+ }
396
+ }
397
+ }
398
+ return patterns;
399
+ }
400
+ /**
401
+ * Detect Kite patterns (Grand Trine with one opposition)
402
+ */
403
+ function detectKites(planets, houseCusps, maxOrb = 8) {
404
+ const patterns = [];
405
+ const grandTrines = detectGrandTrines(planets, houseCusps, maxOrb);
406
+ grandTrines.forEach((grandTrine) => {
407
+ // For each planet in the grand trine, look for opposition to another planet
408
+ grandTrine.planets.forEach((trinePoint) => {
409
+ planets.forEach((planet) => {
410
+ const isPartOfTrine = grandTrine.planets.some((tp) => tp.name === planet.name);
411
+ if (!isPartOfTrine) {
412
+ const trinePointOriginal = planets.find((p) => p.name === trinePoint.name);
413
+ if (trinePointOriginal &&
414
+ hasAspect(trinePointOriginal, planet, 180, maxOrb)) {
415
+ const oppositionPlanet = pointToPlanetPosition(planet, houseCusps);
416
+ const orbToOpposition = calculateOrb(trinePointOriginal, planet, 180);
417
+ const averageOrb = (grandTrine.averageOrb + orbToOpposition) / 2;
418
+ patterns.push({
419
+ type: 'Kite',
420
+ grandTrine: grandTrine.planets,
421
+ opposition: oppositionPlanet,
422
+ averageOrb,
423
+ });
424
+ }
425
+ }
426
+ });
427
+ });
428
+ });
429
+ return patterns;
430
+ }
431
+ /**
432
+ * Main function to detect all aspect patterns
433
+ */
434
+ function detectAspectPatterns(planets, houseCusps) {
435
+ const patterns = [];
436
+ patterns.push(...detectTSquares(planets, houseCusps));
437
+ patterns.push(...detectGrandTrines(planets, houseCusps));
438
+ patterns.push(...detectStelliums(planets, houseCusps));
439
+ patterns.push(...detectGrandCrosses(planets, houseCusps));
440
+ patterns.push(...detectYods(planets, houseCusps));
441
+ patterns.push(...detectMysticRectangles(planets, houseCusps));
442
+ patterns.push(...detectKites(planets, houseCusps));
443
+ return patterns;
444
+ }