@gomeniucivan/ui 1.0.54 → 1.0.55

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.
package/loader.js CHANGED
@@ -23,13 +23,10 @@
23
23
  * use: [{ loader: require.resolve('@gomeniucivan/ui/loader'), options: { rootDir: __dirname } }],
24
24
  */
25
25
 
26
- 'use strict';
27
-
28
- const nodePath = require('path');
29
-
30
- /** Functions whose calls get a `{ path }` second argument injected. */
31
- const TARGET_FNS = ['createStaticStyles', 'createStyles'];
32
- const CALL_RE = new RegExp(`(?:${TARGET_FNS.join('|')})\\s*\\(`, 'g');
26
+ 'use strict';
27
+
28
+ const nodePath = require('path');
29
+ const { injectStylePath } = require('./scripts/stylePathTransform');
33
30
 
34
31
  /**
35
32
  * Resolve the project root directory.
@@ -56,112 +53,16 @@ function resolveRoot(loaderContext) {
56
53
  return process.cwd();
57
54
  }
58
55
 
59
- module.exports = function injectStylePathLoader(source) {
60
- // Fast bail-out
61
- if (!CALL_RE.test(source)) return source;
62
- CALL_RE.lastIndex = 0;
63
-
64
- const resourcePath = this.resourcePath.replace(/\\/g, '/');
65
-
66
- // Skip the factory implementation files themselves
67
- if (
68
- (resourcePath.includes('createStaticStyles') || resourcePath.includes('createStyles')) &&
69
- resourcePath.endsWith('index.ts')
70
- ) {
71
- return source;
72
- }
73
-
74
- const rootDir = resolveRoot(this);
75
-
76
- // Relative path from project root, forward slashes, no extension
77
- const filePath = nodePath
56
+ module.exports = function injectStylePathLoader(source) {
57
+ const resourcePath = this.resourcePath.replace(/\\/g, '/');
58
+
59
+ const rootDir = resolveRoot(this);
60
+
61
+ // Relative path from project root, forward slashes, no extension
62
+ const filePath = nodePath
78
63
  .relative(rootDir, this.resourcePath)
79
- .replace(/\\/g, '/')
80
- .replace(/\.\w+$/, '');
81
-
82
- // Find every target function call
83
- const positions = [];
84
- let m;
85
- while ((m = CALL_RE.exec(source)) !== null) {
86
- // Skip if inside a comment
87
- const lineStart = source.lastIndexOf('\n', m.index) + 1;
88
- const lineText = source.slice(lineStart, m.index).trimStart();
89
- if (lineText.startsWith('*') || lineText.startsWith('//')) continue;
90
- positions.push(m.index + m[0].length); // right after opening `(`
91
- }
92
-
93
- if (positions.length === 0) return source;
94
-
95
- // Process in reverse so indices don't shift
96
- let result = source;
97
- for (let ci = positions.length - 1; ci >= 0; ci--) {
98
- const afterParen = positions[ci];
99
-
100
- // Count parens to find matching close (skip strings and template literals)
101
- let depth = 1;
102
- let closeIdx = -1;
103
- let inStr = false;
104
- let strCh = '';
105
- let inTpl = false;
106
- let tplDepth = 0;
107
-
108
- for (let i = afterParen; i < result.length; i++) {
109
- const ch = result[i];
110
- const prev = i > 0 ? result[i - 1] : '';
111
-
112
- if (inStr) {
113
- if (ch === strCh && prev !== '\\') inStr = false;
114
- continue;
115
- }
116
- if (inTpl) {
117
- if (ch === '`' && prev !== '\\') {
118
- inTpl = false;
119
- continue;
120
- }
121
- if (ch === '$' && result[i + 1] === '{') {
122
- tplDepth++;
123
- i++;
124
- continue;
125
- }
126
- if (ch === '}' && tplDepth > 0) {
127
- tplDepth--;
128
- continue;
129
- }
130
- continue;
131
- }
132
- if (ch === '"' || ch === "'") {
133
- inStr = true;
134
- strCh = ch;
135
- continue;
136
- }
137
- if (ch === '`') {
138
- inTpl = true;
139
- tplDepth = 0;
140
- continue;
141
- }
142
- if (ch === '(') depth++;
143
- if (ch === ')') {
144
- depth--;
145
- if (depth === 0) {
146
- closeIdx = i;
147
- break;
148
- }
149
- }
150
- }
151
-
152
- if (closeIdx === -1) continue;
153
-
154
- // Skip if already has a path option
155
- const inner = result.slice(afterParen, closeIdx);
156
- if (inner.includes('path:')) continue;
157
-
158
- const hasTrailingComma = /,\s*$/.test(inner);
159
- const pathArg = hasTrailingComma
160
- ? ` { path: '${filePath}' }`
161
- : `, { path: '${filePath}' }`;
162
-
163
- result = result.slice(0, closeIdx) + pathArg + result.slice(closeIdx);
164
- }
165
-
166
- return result;
167
- };
64
+ .replace(/\\/g, '/')
65
+ .replace(/\.\w+$/, '');
66
+
67
+ return injectStylePath(source, filePath, resourcePath);
68
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gomeniucivan/ui",
3
- "version": "1.0.54",
3
+ "version": "1.0.55",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css"
@@ -21,7 +21,8 @@
21
21
  "files": [
22
22
  "dist",
23
23
  "loader.js",
24
- "next-plugin.js"
24
+ "next-plugin.js",
25
+ "scripts/stylePathTransform.js"
25
26
  ],
26
27
  "scripts": {
27
28
  "build": "tsup",
@@ -0,0 +1,229 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Functions whose calls get a `{ path }` option injected.
5
+ */
6
+ const TARGET_FNS = ['createStaticStyles', 'createStyles'];
7
+ const CALL_RE = new RegExp(`(?:${TARGET_FNS.join('|')})\\s*\\(`, 'g');
8
+
9
+ const hasPathProperty = (text) => /\bpath\s*:/.test(text);
10
+
11
+ const escapePathValue = (value) => value.replace(/\\/g, '/').replace(/'/g, "\\'");
12
+
13
+ const injectPathIntoObjectLiteral = (objectText, pathValue) => {
14
+ const trimmed = objectText.trim();
15
+
16
+ if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) return null;
17
+ if (hasPathProperty(trimmed)) return objectText;
18
+
19
+ const body = trimmed.slice(1, -1).trim();
20
+ const injected =
21
+ body.length === 0
22
+ ? `{ path: '${escapePathValue(pathValue)}' }`
23
+ : `{ path: '${escapePathValue(pathValue)}', ${body} }`;
24
+
25
+ const leading = objectText.match(/^\s*/)?.[0] ?? '';
26
+ const trailing = objectText.match(/\s*$/)?.[0] ?? '';
27
+ return `${leading}${injected}${trailing}`;
28
+ };
29
+
30
+ /**
31
+ * Find the matching `)` for a call starting right after `(` and collect
32
+ * top-level argument commas.
33
+ */
34
+ const findCallBoundaries = (source, afterParen) => {
35
+ let depth = 1;
36
+ let braceDepth = 0;
37
+ let bracketDepth = 0;
38
+ let closeIdx = -1;
39
+ const topLevelCommas = [];
40
+
41
+ let inStr = false;
42
+ let strCh = '';
43
+ let inTpl = false;
44
+ let inLineComment = false;
45
+ let inBlockComment = false;
46
+
47
+ for (let i = afterParen; i < source.length; i++) {
48
+ const ch = source[i];
49
+ const prev = i > 0 ? source[i - 1] : '';
50
+ const next = i + 1 < source.length ? source[i + 1] : '';
51
+
52
+ if (inLineComment) {
53
+ if (ch === '\n') inLineComment = false;
54
+ continue;
55
+ }
56
+
57
+ if (inBlockComment) {
58
+ if (ch === '*' && next === '/') {
59
+ inBlockComment = false;
60
+ i++;
61
+ }
62
+ continue;
63
+ }
64
+
65
+ if (inStr) {
66
+ if (ch === strCh && prev !== '\\') inStr = false;
67
+ continue;
68
+ }
69
+
70
+ if (inTpl) {
71
+ if (ch === '`' && prev !== '\\') {
72
+ inTpl = false;
73
+ }
74
+ continue;
75
+ }
76
+
77
+ if (ch === '/' && next === '/') {
78
+ inLineComment = true;
79
+ i++;
80
+ continue;
81
+ }
82
+
83
+ if (ch === '/' && next === '*') {
84
+ inBlockComment = true;
85
+ i++;
86
+ continue;
87
+ }
88
+
89
+ if (ch === '"' || ch === "'") {
90
+ inStr = true;
91
+ strCh = ch;
92
+ continue;
93
+ }
94
+
95
+ if (ch === '`') {
96
+ inTpl = true;
97
+ continue;
98
+ }
99
+
100
+ if (ch === '{') {
101
+ braceDepth++;
102
+ continue;
103
+ }
104
+
105
+ if (ch === '}') {
106
+ if (braceDepth > 0) braceDepth--;
107
+ continue;
108
+ }
109
+
110
+ if (ch === '[') {
111
+ bracketDepth++;
112
+ continue;
113
+ }
114
+
115
+ if (ch === ']') {
116
+ if (bracketDepth > 0) bracketDepth--;
117
+ continue;
118
+ }
119
+
120
+ if (ch === '(') {
121
+ depth++;
122
+ continue;
123
+ }
124
+
125
+ if (ch === ')') {
126
+ depth--;
127
+ if (depth === 0) {
128
+ closeIdx = i;
129
+ break;
130
+ }
131
+ continue;
132
+ }
133
+
134
+ if (ch === ',' && depth === 1 && braceDepth === 0 && bracketDepth === 0) {
135
+ topLevelCommas.push(i);
136
+ }
137
+ }
138
+
139
+ if (closeIdx === -1) return null;
140
+ return { closeIdx, topLevelCommas };
141
+ };
142
+
143
+ /**
144
+ * Inject `{ path: '<file-path>' }` into createStyles/createStaticStyles calls.
145
+ *
146
+ * Rules:
147
+ * - One arg call: append second arg `{ path }`
148
+ * - Two+ arg call:
149
+ * - if second arg is object literal and has no `path`, inject into object
150
+ * - otherwise append third arg `{ path }` as a fallback
151
+ */
152
+ const injectStylePath = (source, filePath, resourcePath = '') => {
153
+ if (!CALL_RE.test(source)) return source;
154
+ CALL_RE.lastIndex = 0;
155
+
156
+ const normalizedResourcePath = resourcePath.replace(/\\/g, '/');
157
+
158
+ // Skip the style factory implementation files themselves.
159
+ if (
160
+ (normalizedResourcePath.includes('createStaticStyles') ||
161
+ normalizedResourcePath.includes('createStyles')) &&
162
+ normalizedResourcePath.endsWith('index.ts')
163
+ ) {
164
+ return source;
165
+ }
166
+
167
+ const positions = [];
168
+ let match;
169
+ while ((match = CALL_RE.exec(source)) !== null) {
170
+ const lineStart = source.lastIndexOf('\n', match.index) + 1;
171
+ const lineText = source.slice(lineStart, match.index).trimStart();
172
+ if (lineText.startsWith('*') || lineText.startsWith('//')) continue;
173
+ positions.push(match.index + match[0].length);
174
+ }
175
+
176
+ if (positions.length === 0) return source;
177
+
178
+ let result = source;
179
+ const escapedPath = escapePathValue(filePath);
180
+
181
+ for (let pi = positions.length - 1; pi >= 0; pi--) {
182
+ const afterParen = positions[pi];
183
+ const callInfo = findCallBoundaries(result, afterParen);
184
+ if (!callInfo) continue;
185
+
186
+ const { closeIdx, topLevelCommas } = callInfo;
187
+
188
+ // Single-arg call: add options as second arg.
189
+ if (topLevelCommas.length === 0) {
190
+ const inner = result.slice(afterParen, closeIdx);
191
+ const hasTrailingComma = /,\s*$/.test(inner);
192
+ result =
193
+ result.slice(0, closeIdx) +
194
+ (hasTrailingComma ? ` { path: '${escapedPath}' }` : `, { path: '${escapedPath}' }`) +
195
+ result.slice(closeIdx);
196
+ continue;
197
+ }
198
+
199
+ // Two+ args: patch second arg when it's an object literal.
200
+ const secondStart = topLevelCommas[0] + 1;
201
+ const secondEnd = topLevelCommas[1] ?? closeIdx;
202
+ const secondArgRaw = result.slice(secondStart, secondEnd);
203
+
204
+ if (hasPathProperty(secondArgRaw)) continue;
205
+
206
+ const injectedSecondArg = injectPathIntoObjectLiteral(secondArgRaw, filePath);
207
+ if (injectedSecondArg !== null) {
208
+ result =
209
+ result.slice(0, secondStart) +
210
+ injectedSecondArg +
211
+ result.slice(secondEnd);
212
+ continue;
213
+ }
214
+
215
+ // Fallback for non-object second args.
216
+ const inner = result.slice(afterParen, closeIdx);
217
+ const hasTrailingComma = /,\s*$/.test(inner);
218
+ result =
219
+ result.slice(0, closeIdx) +
220
+ (hasTrailingComma ? ` { path: '${escapedPath}' }` : `, { path: '${escapedPath}' }`) +
221
+ result.slice(closeIdx);
222
+ }
223
+
224
+ return result;
225
+ };
226
+
227
+ module.exports = {
228
+ injectStylePath,
229
+ };