@ciolabs/html-find-conditional-comments
Version:
Finds all conditional comments in a string
1 lines • 4.52 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export interface ConditionalComment {\n /**\n * Whether the item is a comment\n */\n isComment: boolean;\n\n /**\n * Opening portion of the conditional comment.\n */\n open: string;\n\n /**\n * Closing portion of the conditional comment.\n */\n close: string;\n\n /**\n * Whether the comment \"bubbles\" around the value.\n */\n bubble: boolean;\n\n /**\n * Either \"revealed\" or \"hidden\".\n */\n downlevel: 'revealed' | 'hidden';\n\n /**\n * A range array containing the start and end indices of the comment.\n */\n range: [number, number];\n}\n\n// Token regexes to support nested conditional comments\nconst OPEN_REGEX = /<!(--)?\\[if\\s[\\s\\w!&()|]+]>(?:<!--+>)?/gi;\n// Capture whether the close carries trailing dashes (\"--\") before '>' to enforce symmetry\nconst CLOSE_REGEX = /(?:<!--)?<!\\[endif](--)?>/gi;\n\n/**\n * Finds the conditional comments in HTML.\n */\nexport default function findConditionalComments(string_: string): ConditionalComment[] {\n const comments: ConditionalComment[] = [];\n\n // Use a stack to handle nested conditional comments\n const stack: Array<{\n open: string;\n start: number;\n end: number;\n isComment: boolean;\n bubble: boolean;\n }> = [];\n let position = 0;\n\n while (position < string_.length) {\n // Find next open and next close from current position\n OPEN_REGEX.lastIndex = position;\n CLOSE_REGEX.lastIndex = position;\n\n const openMatch = OPEN_REGEX.exec(string_);\n const closeMatch = CLOSE_REGEX.exec(string_);\n\n // If neither token is found, we're done\n if (!openMatch && !closeMatch) {\n break;\n }\n\n // Choose the earliest token occurrence\n const nextOpenIndex = openMatch ? openMatch.index : Number.POSITIVE_INFINITY;\n const nextCloseIndex = closeMatch ? closeMatch.index : Number.POSITIVE_INFINITY;\n\n if (nextOpenIndex < nextCloseIndex && openMatch) {\n // Process opening token\n const openText = openMatch[0];\n const openStart = openMatch.index;\n const openEnd = OPEN_REGEX.lastIndex;\n\n const isComment = openText.startsWith('<!--');\n const bubble = openText.endsWith('-->');\n\n stack.push({\n open: openText,\n start: openStart,\n end: openEnd,\n isComment,\n bubble,\n });\n\n position = openEnd;\n continue;\n }\n\n // Process closing token\n if (closeMatch) {\n const closeText = closeMatch[0];\n const closeEnd = CLOSE_REGEX.lastIndex;\n\n if (stack.length > 0) {\n const openState = stack.at(-1)!;\n const closeHasDashes = Boolean(closeMatch[1]);\n const openRequiresDashes = openState.isComment; // HTML comment style requires '-->'\n\n if (closeHasDashes === openRequiresDashes) {\n // Valid matching close for the most recent open\n stack.pop();\n comments.push({\n isComment: openState.isComment,\n open: openState.open,\n close: closeText,\n bubble: openState.bubble,\n downlevel: openState.bubble || !openState.isComment ? 'revealed' : 'hidden',\n range: [openState.start, closeEnd],\n });\n }\n }\n\n position = closeEnd;\n }\n }\n\n return comments;\n}\n"],"mappings":";AAiCA,IAAM,aAAa;AAEnB,IAAM,cAAc;AAKL,SAAR,wBAAyC,SAAuC;AACrF,QAAM,WAAiC,CAAC;AAGxC,QAAM,QAMD,CAAC;AACN,MAAI,WAAW;AAEf,SAAO,WAAW,QAAQ,QAAQ;AAEhC,eAAW,YAAY;AACvB,gBAAY,YAAY;AAExB,UAAM,YAAY,WAAW,KAAK,OAAO;AACzC,UAAM,aAAa,YAAY,KAAK,OAAO;AAG3C,QAAI,CAAC,aAAa,CAAC,YAAY;AAC7B;AAAA,IACF;AAGA,UAAM,gBAAgB,YAAY,UAAU,QAAQ,OAAO;AAC3D,UAAM,iBAAiB,aAAa,WAAW,QAAQ,OAAO;AAE9D,QAAI,gBAAgB,kBAAkB,WAAW;AAE/C,YAAM,WAAW,UAAU,CAAC;AAC5B,YAAM,YAAY,UAAU;AAC5B,YAAM,UAAU,WAAW;AAE3B,YAAM,YAAY,SAAS,WAAW,MAAM;AAC5C,YAAM,SAAS,SAAS,SAAS,KAAK;AAEtC,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,OAAO;AAAA,QACP,KAAK;AAAA,QACL;AAAA,QACA;AAAA,MACF,CAAC;AAED,iBAAW;AACX;AAAA,IACF;AAGA,QAAI,YAAY;AACd,YAAM,YAAY,WAAW,CAAC;AAC9B,YAAM,WAAW,YAAY;AAE7B,UAAI,MAAM,SAAS,GAAG;AACpB,cAAM,YAAY,MAAM,GAAG,EAAE;AAC7B,cAAM,iBAAiB,QAAQ,WAAW,CAAC,CAAC;AAC5C,cAAM,qBAAqB,UAAU;AAErC,YAAI,mBAAmB,oBAAoB;AAEzC,gBAAM,IAAI;AACV,mBAAS,KAAK;AAAA,YACZ,WAAW,UAAU;AAAA,YACrB,MAAM,UAAU;AAAA,YAChB,OAAO;AAAA,YACP,QAAQ,UAAU;AAAA,YAClB,WAAW,UAAU,UAAU,CAAC,UAAU,YAAY,aAAa;AAAA,YACnE,OAAO,CAAC,UAAU,OAAO,QAAQ;AAAA,UACnC,CAAC;AAAA,QACH;AAAA,MACF;AAEA,iBAAW;AAAA,IACb;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}