(attrStr, jPath, tagName, force = false)
| 198 | const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])([\\s\\S]*?)\\3)?', 'gm'); |
| 199 | |
| 200 | function buildAttributesMap(attrStr, jPath, tagName, force = false) { |
| 201 | const options = this.options; |
| 202 | if (force === true || (options.ignoreAttributes !== true && typeof attrStr === 'string')) { |
| 203 | // attrStr = attrStr.replace(/\r?\n/g, ' '); |
| 204 | //attrStr = attrStr || attrStr.trim(); |
| 205 | |
| 206 | const matches = getAllMatches(attrStr, attrsRegx); |
| 207 | const len = matches.length; //don't make it inline |
| 208 | const attrs = {}; |
| 209 | |
| 210 | // Pre-process values once: trim + entity replacement |
| 211 | // Reused in both matcher update and second pass |
| 212 | const processedVals = new Array(len); |
| 213 | let hasRawAttrs = false; |
| 214 | const rawAttrsForMatcher = {}; |
| 215 | |
| 216 | for (let i = 0; i < len; i++) { |
| 217 | const attrName = this.resolveNameSpace(matches[i][1]); |
| 218 | const oldVal = matches[i][4]; |
| 219 | |
| 220 | if (attrName.length && oldVal !== undefined) { |
| 221 | let val = oldVal; |
| 222 | if (options.trimValues) val = val.trim(); |
| 223 | val = this.replaceEntitiesValue(val, tagName, this.readonlyMatcher); |
| 224 | processedVals[i] = val; |
| 225 | |
| 226 | rawAttrsForMatcher[attrName] = val; |
| 227 | hasRawAttrs = true; |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | // Update matcher ONCE before second pass, if applicable |
| 232 | if (hasRawAttrs && typeof jPath === 'object' && jPath.updateCurrent) { |
| 233 | jPath.updateCurrent(rawAttrsForMatcher); |
| 234 | } |
| 235 | |
| 236 | // Hoist toString() once — path doesn't change during attribute processing |
| 237 | const jPathStr = options.jPath ? jPath.toString() : this.readonlyMatcher; |
| 238 | |
| 239 | // Second pass: apply processors, build final attrs |
| 240 | let hasAttrs = false; |
| 241 | for (let i = 0; i < len; i++) { |
| 242 | const attrName = this.resolveNameSpace(matches[i][1]); |
| 243 | |
| 244 | if (this.ignoreAttributesFn(attrName, jPathStr)) continue; |
| 245 | |
| 246 | let aName = options.attributeNamePrefix + attrName; |
| 247 | |
| 248 | if (attrName.length) { |
| 249 | if (options.transformAttributeName) { |
| 250 | aName = options.transformAttributeName(aName); |
| 251 | } |
| 252 | aName = sanitizeName(aName, options); |
| 253 | |
| 254 | if (matches[i][4] !== undefined) { |
| 255 | // Reuse already-processed value — no double entity replacement |
| 256 | const oldVal = processedVals[i]; |
| 257 |
nothing calls this directly
no test coverage detected