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