{"version":3,"file":"index.mjs","sources":["../src/ts/AnthologyClient.ts"],"sourcesContent":["// --- Imports -------------------------------------------------------------- //\n\nimport { AnthologyRule, ExtractOptions } from './types';\n\n// --- Business logic ------------------------------------------------------- //\n\nexport class AnthologyClient<BreakpointNames extends string> {\n  // --- Properties --- //\n\n  private metadata: any;\n  private styleSheet: StyleSheet;\n  private rules: CSSRule[];\n\n  // --- Constructor --- //\n\n  constructor(styleSheet: StyleSheet = AnthologyClient.StyleSheets[0]) {\n    if (!styleSheet && !AnthologyClient.StyleSheets[0]) {\n      throw new Error(\n        'Could not find any style sheets containing Anthology.scss metadata.',\n      );\n    }\n\n    this.styleSheet = styleSheet;\n    this.parseMetadata();\n  }\n\n  // --- Getters --- //\n\n  /**\n   * Get all Anthology-compatible style sheets in the document.\n   *\n   * @readonly\n   * @static\n   * @memberof Anthology\n   */\n  public static get StyleSheets(): StyleSheet[] {\n    // TODO: memoize\n    const styleSheets = Array.from(document.styleSheets);\n\n    return styleSheets.filter(rawSheet => {\n      if (!rawSheet['rules'] && !rawSheet['cssRules']) return false;\n      const cssSheet = rawSheet as CSSStyleSheet;\n      const rules = (Array.from(\n        cssSheet.rules || cssSheet.cssRules,\n      ) as unknown) as CSSStyleRule[];\n      return !!rules.find(\n        rule => rule.selectorText === '-anthology-metadata::before',\n      );\n    });\n  }\n\n  /**\n   * Get breakpoints configured for this instance of `Anthology.scss`.\n   *\n   * @readonly\n   * @type {{ [key in BreakpointNames]: string }}\n   * @memberof Anthology\n   */\n  public get breakpoints(): { [key in BreakpointNames]: string } {\n    // TODO: add more functionality here (i.e.: media query helpers for JS).\n    return this.metadata.config.breakpoints;\n  }\n\n  // --- Methods --- //\n\n  /**\n   * Parse metadata for this instance of `Anthology.scss`.\n   */\n  public parseMetadata(): this {\n    if (!this.styleSheet['rules'] && !this.styleSheet['cssRules']) {\n      throw new Error('Style sheet does not contain any CSS rules.');\n    }\n\n    // Grab the style sheet and cast to proper typing.\n    const cssSheet = this.styleSheet as CSSStyleSheet;\n\n    // Get an array of rules from the sheet.\n    const rules = (Array.from(\n      cssSheet.rules || cssSheet.cssRules,\n    ) as unknown) as CSSRule[];\n\n    // Find the metadata rule.\n    const metadataRule: CSSStyleRule = rules.find(rule => {\n      return (\n        (rule as CSSStyleRule).selectorText === '-anthology-metadata::before'\n      );\n    }) as CSSStyleRule;\n\n    // Raise an error if metadata is not found.\n    if (!metadataRule) {\n      throw new Error('Style sheet does not contain Anthology.scss metadata.');\n    }\n\n    // Parse metadata (parsing is done twice because the content is provided as a nested string).\n    const metadata = JSON.parse(JSON.parse(metadataRule.style.content));\n\n    this.metadata = metadata;\n    this.rules = rules;\n\n    return this;\n  }\n\n  /**\n   * Extract a rule from within the `Anthology.scss` style sheet on this instance.\n   *\n   * @param {string} shorthand\n   * @param {string} adjective\n   * @param {ExtractOptions} [options={}]\n   * @returns {AnthologyRule}\n   * @memberof AnthologyClient\n   */\n  public extract(\n    shorthand: string,\n    adjective: string,\n    options: ExtractOptions = {},\n  ): AnthologyRule {\n    // TODO: memoize\n    const separator = this.metadata.config.separator;\n    const importantTag = this.metadata.config['important-tag'];\n    const themeTag = this.metadata.config['theme-tag'];\n    const responsiveTag = this.metadata.config['responsive-tag'];\n\n    const important = !!options.important ? `${separator}${importantTag}` : '';\n    const theme = !!options.theme\n      ? `${separator}${themeTag}${options.theme}`\n      : '';\n    const breakpoint = !!options.breakpoint\n      ? `${separator}${responsiveTag}${options.breakpoint}`\n      : '';\n    const pseudo = !!options.pseudo ? `${separator}${options.pseudo}` : '';\n\n    let styleRule: CSSStyleRule;\n    let selector: string;\n    let selectorEscaped: string;\n\n    // Find the first matching CSS Rule\n    const isValidRule = this.rules.find(rule => {\n      // Search through dynamically-responsive rules first.\n      if (!!options.breakpoint && rule.type === CSSRule.MEDIA_RULE) {\n        const mediaRule = rule as CSSMediaRule;\n\n        // If we arrive at the desired breakpoint, search there next!\n        if (\n          mediaRule.conditionText.includes(this.breakpoints[options.breakpoint])\n        ) {\n          // Define selectors\n          selector = `${shorthand}${separator}${adjective}${important}${theme}${pseudo}`;\n          selectorEscaped = CSS.escape(selector);\n\n          // Look through each internal rule...\n          return !!Array.from(mediaRule.cssRules).find(rule => {\n            // Define the rule (for inclusion in return value) and test for a potential match.\n            styleRule = rule as CSSStyleRule;\n            return styleRule.selectorText.includes(selectorEscaped);\n          });\n        }\n      } else if (rule.type === CSSRule.STYLE_RULE) {\n        // Define selectors\n        selector = `${shorthand}${separator}${adjective}${important}${theme}${breakpoint}${pseudo}`;\n        selectorEscaped = CSS.escape(selector);\n\n        // Define the rule (for inclusion in return value) and test for a potential match.\n        styleRule = rule as CSSStyleRule;\n        return styleRule.selectorText.includes(selectorEscaped);\n      }\n    });\n\n    // Throw if the rule is invalid or not found in this style sheet.\n    if (!isValidRule) {\n      throw new Error(\n        `Could not find Anthology-generated rule associated with selector: ${selectorEscaped}`,\n      );\n    }\n\n    // Define `property` and `value` for inclusion in return value.\n    const property = styleRule.style[0];\n    const value = styleRule.style[property];\n\n    return {\n      shorthand,\n      adjective,\n      options,\n      selector,\n      selectorEscaped,\n      property,\n      value,\n      cssRule: styleRule,\n    };\n  }\n\n  /**\n   * A shortcut method to extract the `style` object from a `CSSRule` generated by `Anthology.scss`.\n   *\n   * @param {string} shorthand\n   * @param {string} adjective\n   * @param {ExtractOptions} [options={}]\n   * @returns {CSSStyleDeclaration}\n   * @memberof AnthologyClient\n   */\n  public extractStyle(\n    shorthand: string,\n    adjective: string,\n    options: ExtractOptions = {},\n  ): CSSStyleDeclaration {\n    return this.extract(shorthand, adjective, options).cssRule.style;\n  }\n\n  /**\n   * A shortcut method to extract the _unescaped_ selector string from a `CSSRule` generated by `Anthology.scss`.\n   *\n   * @param {string} shorthand\n   * @param {string} adjective\n   * @param {ExtractOptions} [options={}]\n   * @returns {CSSStyleDeclaration}\n   * @memberof AnthologyClient\n   */\n  public extractSelector(\n    shorthand: string,\n    adjective: string,\n    options: ExtractOptions = {},\n  ): string {\n    return this.extract(shorthand, adjective, options).selector;\n  }\n\n  /**\n   * A shortcut method to extract the _escaped_ selector string from a `CSSRule` generated by `Anthology.scss`.\n   *\n   * @param {string} shorthand\n   * @param {string} adjective\n   * @param {ExtractOptions} [options={}]\n   * @returns {CSSStyleDeclaration}\n   * @memberof AnthologyClient\n   */\n  public extractSelectorEscaped(\n    shorthand: string,\n    adjective: string,\n    options: ExtractOptions = {},\n  ): string {\n    return this.extract(shorthand, adjective, options).selectorEscaped;\n  }\n\n  /**\n   * A shortcut method to extract the `property` from a `CSSRule` generated by `Anthology.scss`.\n   *\n   * @param {string} shorthand\n   * @param {string} adjective\n   * @param {ExtractOptions} [options={}]\n   * @returns {CSSStyleDeclaration}\n   * @memberof AnthologyClient\n   */\n  public extractProperty(\n    shorthand: string,\n    adjective: string,\n    options: ExtractOptions = {},\n  ): string {\n    return this.extract(shorthand, adjective, options).property;\n  }\n\n  /**\n   * A shortcut method to extract the `value` from a `CSSRule` generated by `Anthology.scss`.\n   *\n   * @param {string} shorthand\n   * @param {string} adjective\n   * @param {ExtractOptions} [options={}]\n   * @returns {CSSStyleDeclaration}\n   * @memberof AnthologyClient\n   */\n  public extractValue(\n    shorthand: string,\n    adjective: string,\n    options: ExtractOptions = {},\n  ): string {\n    return this.extract(shorthand, adjective, options).value;\n  }\n}\n"],"names":["AnthologyClient","styleSheet","StyleSheets","Error","this","parseMetadata","Array","from","document","styleSheets","filter","rawSheet","rules","cssRules","find","rule","selectorText","breakpoints","metadata","config","const","cssSheet","metadataRule","JSON","parse","style","content","extract","shorthand","adjective","options","styleRule","selector","selectorEscaped","separator","important","theme","breakpoint","pseudo","type","CSSRule","MEDIA_RULE","mediaRule","conditionText","includes","CSS","escape","STYLE_RULE","property","extractStyle","cssRule","extractSelector","extractSelectorEscaped","extractProperty","extractValue","value"],"mappings":"IAMaA,EASX,WAAYC,qBAAyBD,EAAgBE,YAAY,KAC1DD,IAAeD,EAAgBE,YAAY,GAC9C,MAAM,IAAIC,MACR,uEAIJC,KAAKH,WAAaA,EAClBG,KAAKC,uFAYWH,2BAIhB,OAFoBI,MAAMC,KAAKC,SAASC,aAErBC,gBAAOC,OACnBA,EAAgB,QAAMA,EAAmB,SAAG,OAAO,EAKxD,QAHeL,MAAMC,KADJI,EAENC,OAFMD,EAEYE,UAEdC,cACbC,SAA8B,gCAAtBA,EAAKC,oBAYRC,kCAEFb,KAAKc,SAASC,OAAOF,yBAQvBZ,yBACL,IAAKD,KAAKH,WAAkB,QAAMG,KAAKH,WAAqB,SAC1D,MAAM,IAAIE,MAAM,+CAIlBiB,IAAMC,EAAWjB,KAAKH,WAGhBW,EAASN,MAAMC,KACnBc,EAAST,OAASS,EAASR,UAIvBS,EAA6BV,EAAME,cAAKC,SAEF,gCAAvCA,EAAsBC,mBAKtBM,EACH,MAAM,IAAInB,MAAM,yDAIlBiB,IAAMF,EAAWK,KAAKC,MAAMD,KAAKC,MAAMF,EAAaG,MAAMC,iBAE1DtB,KAAKc,SAAWA,EAChBd,KAAKQ,MAAQA,EAENR,kBAYFuB,iBACLC,EACAC,EACAC,6BAA0B,QAiBtBC,EACAC,EACAC,EAhBEC,EAAY9B,KAAKc,SAASC,OAAOe,UAKjCC,EAAcL,EAAQK,aAAeD,EAJtB9B,KAAKc,SAASC,OAAO,iBAI8B,GAClEiB,EAAUN,EAAQM,SACjBF,EALU9B,KAAKc,SAASC,OAAO,aAKRW,EAAa,MACvC,GACEO,EAAeP,EAAQO,cACtBH,EAPe9B,KAAKc,SAASC,OAAO,kBAORW,EAAkB,WACjD,GACEQ,EAAWR,EAAQQ,UAAYJ,EAAYJ,EAAc,OAAK,OAOhD1B,KAAKQ,MAAME,cAAKC,GAElC,GAAMe,EAAQO,YAActB,EAAKwB,OAASC,QAAQC,WAAY,CAC5DrB,IAAMsB,EAAY3B,EAGlB,GACE2B,EAAUC,cAAcC,SAASxC,EAAKa,YAAYa,EAAQO,aAO1D,OAJAL,EAAW,GAAGJ,EAAYM,EAAYL,EAAYM,EAAYC,EAAQE,IACpDO,IAAIC,OAAOd,KAGpB1B,MAAMC,KAAKmC,EAAU7B,UAAUC,cAAKC,YAE/BA,GACKC,aAAa4B,SAASX,UAGtC,GAAIlB,EAAKwB,OAASC,QAAQO,kBAE/Bf,EAAW,GAAGJ,EAAYM,EAAYL,EAAYM,EAAYC,EAAQC,EAAaC,IACjEO,IAAIC,OAAOd,MAGjBjB,GACKC,aAAa4B,SAASX,WAMnC,IAAI9B,2EAC6D8B,OAKnEe,EAAWjB,EAAUN,MAAM,GAGjC,MAAO,WACLG,YACAC,UACAC,WACAE,kBACAC,WACAe,QARYjB,EAAUN,MAAMuB,WAUnBjB,gBAaNkB,sBACLrB,EACAC,EACAC,GAEA,sBAF0B,IAEnB1B,KAAKuB,QAAQC,EAAWC,EAAWC,GAASoB,QAAQzB,mBAYtD0B,yBACLvB,EACAC,EACAC,GAEA,sBAF0B,IAEnB1B,KAAKuB,QAAQC,EAAWC,EAAWC,GAASE,sBAY9CoB,gCACLxB,EACAC,EACAC,GAEA,sBAF0B,IAEnB1B,KAAKuB,QAAQC,EAAWC,EAAWC,GAASG,6BAY9CoB,yBACLzB,EACAC,EACAC,GAEA,sBAF0B,IAEnB1B,KAAKuB,QAAQC,EAAWC,EAAWC,GAASkB,sBAY9CM,sBACL1B,EACAC,EACAC,GAEA,sBAF0B,IAEnB1B,KAAKuB,QAAQC,EAAWC,EAAWC,GAASyB"}