@thyn/core 0.0.352 → 0.0.353

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.
@@ -1,12 +1,13 @@
1
1
  export function extractParts(code) {
2
2
  // Helper to check if a position is inside a string literal or comment
3
- function isInsideStringOrComment(code, pos) {
3
+ // within a specific range (used for checking script content only)
4
+ function isInsideStringOrComment(code, startPos, endPos) {
4
5
  let inString = false;
5
6
  let stringChar = '';
6
7
  let escaped = false;
7
8
  let inLineComment = false;
8
9
  let inBlockComment = false;
9
- for (let i = 0; i < pos; i++) {
10
+ for (let i = startPos; i < endPos; i++) {
10
11
  const char = code[i];
11
12
  const nextChar = code[i + 1];
12
13
  if (inLineComment) {
@@ -52,45 +53,114 @@ export function extractParts(code) {
52
53
  }
53
54
  return inString || inLineComment || inBlockComment;
54
55
  }
55
- // Find first real <script> tag (not inside a string)
56
- function findScriptSection(code) {
56
+ // Find all script tag positions with their boundaries
57
+ function findScriptBoundaries(code) {
58
+ const boundaries = [];
57
59
  const openRegex = /<script([^>]*)>/gi;
60
+ const closeRegex = /<\/script>/gi;
58
61
  let openMatch;
59
62
  while ((openMatch = openRegex.exec(code)) !== null) {
60
- if (!isInsideStringOrComment(code, openMatch.index)) {
61
- const contentStart = openMatch.index + openMatch[0].length;
62
- // Find the first </script> that is not inside a string
63
- const closeRegex = /<\/script>/gi;
64
- let closeMatch;
65
- while ((closeMatch = closeRegex.exec(code)) !== null) {
66
- if (closeMatch.index >= contentStart && !isInsideStringOrComment(code, closeMatch.index)) {
67
- return {
68
- start: openMatch.index,
69
- contentStart: contentStart,
70
- contentEnd: closeMatch.index,
71
- end: closeMatch.index + closeMatch[0].length,
72
- attrs: openMatch[1] || ''
73
- };
63
+ const openIndex = openMatch.index;
64
+ const openLength = openMatch[0].length;
65
+ const attrs = openMatch[1] || '';
66
+ // Find matching close tag
67
+ closeRegex.lastIndex = openIndex + openLength;
68
+ let closeMatch;
69
+ while ((closeMatch = closeRegex.exec(code)) !== null) {
70
+ // Check if this close tag is inside a JS string within this script
71
+ const contentStart = openIndex + openLength;
72
+ if (!isInsideStringOrComment(code, contentStart, closeMatch.index)) {
73
+ boundaries.push({
74
+ start: openIndex,
75
+ end: closeMatch.index + closeMatch[0].length,
76
+ attrs
77
+ });
78
+ break;
79
+ }
80
+ }
81
+ }
82
+ return boundaries;
83
+ }
84
+ // Find the real script section (not inside a string of another script)
85
+ function findScriptSection(code) {
86
+ const allBoundaries = findScriptBoundaries(code);
87
+ if (allBoundaries.length === 0)
88
+ return null;
89
+ // The first script tag is the real one if it's not inside any other script's string
90
+ // Check each boundary to see if it's inside another script's content
91
+ for (const boundary of allBoundaries) {
92
+ let isInsideAnotherScript = false;
93
+ for (const other of allBoundaries) {
94
+ if (other === boundary)
95
+ continue;
96
+ // Check if this boundary is inside another script's content
97
+ const otherContentStart = other.start + code.slice(other.start, other.end).indexOf('>') + 1;
98
+ const otherContentEnd = other.end - code.slice(other.end - 10, other.end).indexOf('<') - 10 + code.slice(other.end - 10, other.end).indexOf('<');
99
+ if (boundary.start > otherContentStart && boundary.start < other.end) {
100
+ // This boundary is inside another script's content area
101
+ // Check if it's inside a JS string
102
+ if (isInsideStringOrComment(code, otherContentStart, boundary.start)) {
103
+ isInsideAnotherScript = true;
104
+ break;
74
105
  }
75
106
  }
76
107
  }
108
+ if (!isInsideAnotherScript) {
109
+ // This is the real script section
110
+ const openTagEnd = code.indexOf('>', boundary.start) + 1;
111
+ const closeTagStart = code.lastIndexOf('<', boundary.end - 1);
112
+ return {
113
+ start: boundary.start,
114
+ contentStart: openTagEnd,
115
+ contentEnd: closeTagStart,
116
+ end: boundary.end,
117
+ attrs: boundary.attrs
118
+ };
119
+ }
77
120
  }
78
121
  return null;
79
122
  }
80
- // Find first real <style> tag (not inside a string)
123
+ // Find the real style section (outside of script sections)
81
124
  function findStyleSection(code) {
125
+ const scriptBoundaries = findScriptBoundaries(code);
82
126
  const openRegex = /<style[^>]*>/gi;
127
+ const closeRegex = /<\/style>/gi;
83
128
  let openMatch;
84
129
  while ((openMatch = openRegex.exec(code)) !== null) {
85
- if (!isInsideStringOrComment(code, openMatch.index)) {
86
- const contentStart = openMatch.index + openMatch[0].length;
87
- // Find the first </style> that is not inside a string
88
- const closeRegex = /<\/style>/gi;
130
+ const openIndex = openMatch.index;
131
+ // Check if this style tag is inside any script section
132
+ let isInsideScript = false;
133
+ for (const script of scriptBoundaries) {
134
+ const contentStart = script.start + code.slice(script.start, script.end).indexOf('>') + 1;
135
+ const contentEnd = script.end - code.slice(script.end - 10, script.end).indexOf('<') - 10 + code.slice(script.end - 10, script.end).indexOf('<');
136
+ if (openIndex >= contentStart && openIndex < script.end) {
137
+ // It's in the script section, check if inside a JS string
138
+ if (isInsideStringOrComment(code, contentStart, openIndex)) {
139
+ isInsideScript = true;
140
+ break;
141
+ }
142
+ }
143
+ }
144
+ if (!isInsideScript) {
145
+ // Found a real style tag, now find its close tag
146
+ const contentStart = openIndex + openMatch[0].length;
147
+ closeRegex.lastIndex = contentStart;
89
148
  let closeMatch;
90
149
  while ((closeMatch = closeRegex.exec(code)) !== null) {
91
- if (closeMatch.index >= contentStart && !isInsideStringOrComment(code, closeMatch.index)) {
150
+ // Make sure close tag is also outside scripts
151
+ let closeIsInsideScript = false;
152
+ for (const script of scriptBoundaries) {
153
+ const scriptContentStart = script.start + code.slice(script.start, script.end).indexOf('>') + 1;
154
+ if (closeMatch.index >= scriptContentStart && closeMatch.index < script.end) {
155
+ if (isInsideStringOrComment(code, scriptContentStart, closeMatch.index)) {
156
+ closeIsInsideScript = true;
157
+ break;
158
+ }
159
+ }
160
+ }
161
+ if (!closeIsInsideScript) {
92
162
  return {
93
- start: openMatch.index,
163
+ start: openIndex,
94
164
  contentStart: contentStart,
95
165
  contentEnd: closeMatch.index,
96
166
  end: closeMatch.index + closeMatch[0].length
@@ -8,7 +8,7 @@
8
8
  "name": "thyn-app",
9
9
  "version": "0.0.0",
10
10
  "devDependencies": {
11
- "@thyn/core": "^0.0.351",
11
+ "@thyn/core": "^0.0.352",
12
12
  "vite": "^6.3.5"
13
13
  }
14
14
  },
@@ -742,9 +742,9 @@
742
742
  ]
743
743
  },
744
744
  "node_modules/@thyn/core": {
745
- "version": "0.0.351",
746
- "resolved": "https://registry.npmjs.org/@thyn/core/-/core-0.0.351.tgz",
747
- "integrity": "sha512-67M0/0wrdz1mNIMZ9V7Nq1jEO1C1iLdoG9rnjFcDGlDQRFM/HlNizvVWOaq2RfapVpgtRqIsKAA5iBloLE2GIA==",
745
+ "version": "0.0.352",
746
+ "resolved": "https://registry.npmjs.org/@thyn/core/-/core-0.0.352.tgz",
747
+ "integrity": "sha512-XvVkZ63CdWxF+OIOnLoxPOesQ0OFlfr/1CY4/LNrZO2QTK4/I92cRlbDaW1ajN3YDSuvf7BeEuWZe5hYn8Jd/Q==",
748
748
  "dev": true,
749
749
  "license": "MIT",
750
750
  "dependencies": {
package/docs/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "preview": "vite preview"
10
10
  },
11
11
  "devDependencies": {
12
- "@thyn/core": "^0.0.351",
12
+ "@thyn/core": "^0.0.352",
13
13
  "vite": "^6.3.5"
14
14
  }
15
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thyn/core",
3
- "version": "0.0.352",
3
+ "version": "0.0.353",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -1,13 +1,14 @@
1
1
  export function extractParts(code: string) {
2
2
  // Helper to check if a position is inside a string literal or comment
3
- function isInsideStringOrComment(code: string, pos: number): boolean {
3
+ // within a specific range (used for checking script content only)
4
+ function isInsideStringOrComment(code: string, startPos: number, endPos: number): boolean {
4
5
  let inString = false;
5
6
  let stringChar = '';
6
7
  let escaped = false;
7
8
  let inLineComment = false;
8
9
  let inBlockComment = false;
9
10
 
10
- for (let i = 0; i < pos; i++) {
11
+ for (let i = startPos; i < endPos; i++) {
11
12
  const char = code[i];
12
13
  const nextChar = code[i + 1];
13
14
 
@@ -61,50 +62,127 @@ export function extractParts(code: string) {
61
62
  return inString || inLineComment || inBlockComment;
62
63
  }
63
64
 
64
- // Find first real <script> tag (not inside a string)
65
- function findScriptSection(code: string): { start: number; contentStart: number; contentEnd: number; end: number; attrs: string } | null {
65
+ // Find all script tag positions with their boundaries
66
+ function findScriptBoundaries(code: string): Array<{ start: number; end: number; attrs: string }> {
67
+ const boundaries = [];
66
68
  const openRegex = /<script([^>]*)>/gi;
69
+ const closeRegex = /<\/script>/gi;
67
70
  let openMatch;
68
71
 
69
72
  while ((openMatch = openRegex.exec(code)) !== null) {
70
- if (!isInsideStringOrComment(code, openMatch.index)) {
71
- const contentStart = openMatch.index + openMatch[0].length;
73
+ const openIndex = openMatch.index;
74
+ const openLength = openMatch[0].length;
75
+ const attrs = openMatch[1] || '';
76
+
77
+ // Find matching close tag
78
+ closeRegex.lastIndex = openIndex + openLength;
79
+ let closeMatch;
80
+ while ((closeMatch = closeRegex.exec(code)) !== null) {
81
+ // Check if this close tag is inside a JS string within this script
82
+ const contentStart = openIndex + openLength;
83
+ if (!isInsideStringOrComment(code, contentStart, closeMatch.index)) {
84
+ boundaries.push({
85
+ start: openIndex,
86
+ end: closeMatch.index + closeMatch[0].length,
87
+ attrs
88
+ });
89
+ break;
90
+ }
91
+ }
92
+ }
93
+
94
+ return boundaries;
95
+ }
96
+
97
+ // Find the real script section (not inside a string of another script)
98
+ function findScriptSection(code: string): { start: number; contentStart: number; contentEnd: number; end: number; attrs: string } | null {
99
+ const allBoundaries = findScriptBoundaries(code);
100
+ if (allBoundaries.length === 0) return null;
101
+
102
+ // The first script tag is the real one if it's not inside any other script's string
103
+ // Check each boundary to see if it's inside another script's content
104
+ for (const boundary of allBoundaries) {
105
+ let isInsideAnotherScript = false;
106
+
107
+ for (const other of allBoundaries) {
108
+ if (other === boundary) continue;
72
109
 
73
- // Find the first </script> that is not inside a string
74
- const closeRegex = /<\/script>/gi;
75
- let closeMatch;
76
- while ((closeMatch = closeRegex.exec(code)) !== null) {
77
- if (closeMatch.index >= contentStart && !isInsideStringOrComment(code, closeMatch.index)) {
78
- return {
79
- start: openMatch.index,
80
- contentStart: contentStart,
81
- contentEnd: closeMatch.index,
82
- end: closeMatch.index + closeMatch[0].length,
83
- attrs: openMatch[1] || ''
84
- };
110
+ // Check if this boundary is inside another script's content
111
+ const otherContentStart = other.start + code.slice(other.start, other.end).indexOf('>') + 1;
112
+ const otherContentEnd = other.end - code.slice(other.end - 10, other.end).indexOf('<') - 10 + code.slice(other.end - 10, other.end).indexOf('<');
113
+
114
+ if (boundary.start > otherContentStart && boundary.start < other.end) {
115
+ // This boundary is inside another script's content area
116
+ // Check if it's inside a JS string
117
+ if (isInsideStringOrComment(code, otherContentStart, boundary.start)) {
118
+ isInsideAnotherScript = true;
119
+ break;
85
120
  }
86
121
  }
87
122
  }
123
+
124
+ if (!isInsideAnotherScript) {
125
+ // This is the real script section
126
+ const openTagEnd = code.indexOf('>', boundary.start) + 1;
127
+ const closeTagStart = code.lastIndexOf('<', boundary.end - 1);
128
+ return {
129
+ start: boundary.start,
130
+ contentStart: openTagEnd,
131
+ contentEnd: closeTagStart,
132
+ end: boundary.end,
133
+ attrs: boundary.attrs
134
+ };
135
+ }
88
136
  }
137
+
89
138
  return null;
90
139
  }
91
140
 
92
- // Find first real <style> tag (not inside a string)
141
+ // Find the real style section (outside of script sections)
93
142
  function findStyleSection(code: string): { start: number; contentStart: number; contentEnd: number; end: number } | null {
143
+ const scriptBoundaries = findScriptBoundaries(code);
94
144
  const openRegex = /<style[^>]*>/gi;
145
+ const closeRegex = /<\/style>/gi;
95
146
  let openMatch;
96
147
 
97
148
  while ((openMatch = openRegex.exec(code)) !== null) {
98
- if (!isInsideStringOrComment(code, openMatch.index)) {
99
- const contentStart = openMatch.index + openMatch[0].length;
149
+ const openIndex = openMatch.index;
150
+
151
+ // Check if this style tag is inside any script section
152
+ let isInsideScript = false;
153
+ for (const script of scriptBoundaries) {
154
+ const contentStart = script.start + code.slice(script.start, script.end).indexOf('>') + 1;
155
+ const contentEnd = script.end - code.slice(script.end - 10, script.end).indexOf('<') - 10 + code.slice(script.end - 10, script.end).indexOf('<');
100
156
 
101
- // Find the first </style> that is not inside a string
102
- const closeRegex = /<\/style>/gi;
157
+ if (openIndex >= contentStart && openIndex < script.end) {
158
+ // It's in the script section, check if inside a JS string
159
+ if (isInsideStringOrComment(code, contentStart, openIndex)) {
160
+ isInsideScript = true;
161
+ break;
162
+ }
163
+ }
164
+ }
165
+
166
+ if (!isInsideScript) {
167
+ // Found a real style tag, now find its close tag
168
+ const contentStart = openIndex + openMatch[0].length;
169
+ closeRegex.lastIndex = contentStart;
103
170
  let closeMatch;
104
171
  while ((closeMatch = closeRegex.exec(code)) !== null) {
105
- if (closeMatch.index >= contentStart && !isInsideStringOrComment(code, closeMatch.index)) {
172
+ // Make sure close tag is also outside scripts
173
+ let closeIsInsideScript = false;
174
+ for (const script of scriptBoundaries) {
175
+ const scriptContentStart = script.start + code.slice(script.start, script.end).indexOf('>') + 1;
176
+ if (closeMatch.index >= scriptContentStart && closeMatch.index < script.end) {
177
+ if (isInsideStringOrComment(code, scriptContentStart, closeMatch.index)) {
178
+ closeIsInsideScript = true;
179
+ break;
180
+ }
181
+ }
182
+ }
183
+ if (!closeIsInsideScript) {
106
184
  return {
107
- start: openMatch.index,
185
+ start: openIndex,
108
186
  contentStart: contentStart,
109
187
  contentEnd: closeMatch.index,
110
188
  end: closeMatch.index + closeMatch[0].length