@teleporthq/teleport-plugin-common 0.43.46 → 0.43.48
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/__tests__/utils/parse-string-with-template-expressions.ts +82 -0
- package/__tests__/utils/route-utils.ts +118 -0
- package/__tests__/utils/template-expression-balance.ts +83 -0
- package/dist/cjs/node-handlers/node-to-jsx/utils.d.ts.map +1 -1
- package/dist/cjs/node-handlers/node-to-jsx/utils.js +30 -7
- package/dist/cjs/node-handlers/node-to-jsx/utils.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils/ast-utils.d.ts.map +1 -1
- package/dist/cjs/utils/ast-utils.js +65 -16
- package/dist/cjs/utils/ast-utils.js.map +1 -1
- package/dist/cjs/utils/route-utils.d.ts +10 -0
- package/dist/cjs/utils/route-utils.d.ts.map +1 -1
- package/dist/cjs/utils/route-utils.js +9 -1
- package/dist/cjs/utils/route-utils.js.map +1 -1
- package/dist/cjs/utils/template-expression-balance.d.ts +58 -0
- package/dist/cjs/utils/template-expression-balance.d.ts.map +1 -0
- package/dist/cjs/utils/template-expression-balance.js +181 -0
- package/dist/cjs/utils/template-expression-balance.js.map +1 -0
- package/dist/esm/node-handlers/node-to-jsx/utils.d.ts.map +1 -1
- package/dist/esm/node-handlers/node-to-jsx/utils.js +31 -8
- package/dist/esm/node-handlers/node-to-jsx/utils.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils/ast-utils.d.ts.map +1 -1
- package/dist/esm/utils/ast-utils.js +66 -17
- package/dist/esm/utils/ast-utils.js.map +1 -1
- package/dist/esm/utils/route-utils.d.ts +10 -0
- package/dist/esm/utils/route-utils.d.ts.map +1 -1
- package/dist/esm/utils/route-utils.js +8 -0
- package/dist/esm/utils/route-utils.js.map +1 -1
- package/dist/esm/utils/template-expression-balance.d.ts +58 -0
- package/dist/esm/utils/template-expression-balance.d.ts.map +1 -0
- package/dist/esm/utils/template-expression-balance.js +174 -0
- package/dist/esm/utils/template-expression-balance.js.map +1 -0
- package/package.json +4 -4
- package/src/node-handlers/node-to-jsx/utils.ts +36 -10
- package/src/utils/ast-utils.ts +68 -17
- package/src/utils/route-utils.ts +9 -0
- package/src/utils/template-expression-balance.ts +196 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-utils.d.ts","sourceRoot":"","sources":["../../../src/utils/route-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"route-utils.d.ts","sourceRoot":"","sources":["../../../src/utils/route-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAG1D;;;GAGG;AACH,eAAO,MAAM,cAAc;;qBACM,MAAM,EAAE;mBAAa,MAAM;;MACxD,OAKH,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAQ,qBAAqB,6BAAE,wBAAwB;;;CAAe,CAAA;AAI7E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,gCAAgC;WAElC,MAAM;;iBAEF,MAAM;mBACJ,MAAM;;wBACe,MAAM;;;eAG9B,aAAa,KACxB,OAiCF,CAAA"}
|
|
@@ -7,6 +7,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
7
7
|
}
|
|
8
8
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
9
9
|
};
|
|
10
|
+
import { RoutePaths } from '@teleporthq/teleport-shared';
|
|
10
11
|
/**
|
|
11
12
|
* True when this UIDL component's output route contains a Next.js dynamic
|
|
12
13
|
* segment (`[id]`, `[slug]`, ...) anywhere in its folder path or file name.
|
|
@@ -15,6 +16,13 @@ export var isDynamicRoute = function (uidl) {
|
|
|
15
16
|
var _a = uidl.outputOptions || {}, _b = _a.folderPath, folderPath = _b === void 0 ? [] : _b, _c = _a.fileName, fileName = _c === void 0 ? '' : _c;
|
|
16
17
|
return __spreadArray(__spreadArray([], folderPath, true), [fileName], false).some(function (segment) { return segment.startsWith('[') && segment.endsWith(']'); });
|
|
17
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* Reading a route TEMPLATE (`/event-details/[id]`) rather than a URL. Defined in
|
|
21
|
+
* teleport-shared because the navlink resolver needs the same two functions and
|
|
22
|
+
* lives in a package that does not depend on this one; re-exported here so
|
|
23
|
+
* `RouteUtils` stays the single import for route questions in the plugins.
|
|
24
|
+
*/
|
|
25
|
+
export var pathHasDynamicSegment = RoutePaths.pathHasDynamicSegment, parseDynamicPathSegments = RoutePaths.parseDynamicPathSegments;
|
|
18
26
|
var MUTATION_NODE_TYPES = new Set(['data-create-item', 'data-update-item']);
|
|
19
27
|
/**
|
|
20
28
|
* True when this page both reads one specific database row via its own
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-utils.js","sourceRoot":"","sources":["../../../src/utils/route-utils.ts"],"names":[],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"route-utils.js","sourceRoot":"","sources":["../../../src/utils/route-utils.ts"],"names":[],"mappings":";;;;;;;;;AACA,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAExD;;;GAGG;AACH,MAAM,CAAC,IAAM,cAAc,GAAG,UAAC,IAE9B;IACO,IAAA,KAAqC,IAAI,CAAC,aAAa,IAAI,EAAE,EAA3D,kBAAe,EAAf,UAAU,mBAAG,EAAE,KAAA,EAAE,gBAAa,EAAb,QAAQ,mBAAG,EAAE,KAA6B,CAAA;IACnE,OAAO,gCAAI,UAAU,UAAE,QAAQ,UAAE,IAAI,CACnC,UAAC,OAAO,IAAK,OAAA,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAhD,CAAgD,CAC9D,CAAA;AACH,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAS,IAAA,qBAAqB,GAA+B,UAAU,sBAAzC,EAAE,wBAAwB,GAAK,UAAU,yBAAf,CAAe;AAE7E,IAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAAC,CAAA;AAE7E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,IAAM,gCAAgC,GAAG,UAC9C,IAOC,EACD,SAAyB;;IAEzB,IAAM,SAAS,GAAG,MAAA,MAAA,IAAI,CAAC,aAAa,0CAAE,eAAe,0CAAE,SAAS,CAAA;IAChE,IAAI,CAAC,SAAS,IAAI,CAAC,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,SAAS,CAAA,EAAE;QACvC,OAAO,KAAK,CAAA;KACb;IAED,IAAM,MAAM,GAAG,CAAA,MAAA,IAAI,CAAC,aAAa,0CAAE,MAAM,MAAI,MAAA,IAAI,CAAC,aAAa,0CAAE,QAAQ,CAAA,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAA;IAE5F,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,UAAC,EAAE;;QAChD,IAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAA;QAC1B,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,MAAM,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,EAAE;YACzE,OAAO,KAAK,CAAA;SACb;QAED,wEAAwE;QACxE,yEAAyE;QACzE,0EAA0E;QAC1E,+CAA+C;QAC/C,IAAM,aAAa,GAAG,MAAA,OAAO,CAAC,MAAM,0CAAE,MAA4B,CAAA;QAClE,IAAM,aAAa,GAAG,MAAA,OAAO,CAAC,MAAM,0CAAE,aAAkD,CAAA;QACxF,IAAM,kBAAkB,GACtB,OAAO,CAAC,KAAK,KAAK,MAAM;YACtB,CAAC,CAAC,CAAC,aAAa,IAAI,aAAa,KAAK,MAAM;YAC5C,CAAC,CAAC,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,UAAC,CAAC,IAAK,OAAA,CAAC,CAAC,EAAE,KAAK,MAAM,EAAf,CAAe,CAAC,CAAA;QAEhG,IAAI,CAAC,kBAAkB,EAAE;YACvB,OAAO,KAAK,CAAA;SACb;QAED,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAClB,UAAC,IAAI,YAAK,OAAA,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,SAAS,MAAK,SAAS,CAAA,EAAA,CACrF,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delimiter balancing for `{{ … }}` binding expressions.
|
|
3
|
+
*
|
|
4
|
+
* THE DEFECT THIS EXISTS FOR. `parseStringWithTemplateExpressions` converted a
|
|
5
|
+
* UIDL string into a template literal and then handed the result straight to
|
|
6
|
+
* Babel. When the binding inside was unbalanced the produced source did not
|
|
7
|
+
* parse, `parse()` threw, and — because the inline-style caller has no
|
|
8
|
+
* try/catch — the SyntaxError escaped all the way out and killed the ENTIRE
|
|
9
|
+
* project build:
|
|
10
|
+
*
|
|
11
|
+
* const x = `translateX(${-(cameraX || ''}px) }px)`
|
|
12
|
+
* ^ Unexpected token, expected ","
|
|
13
|
+
*
|
|
14
|
+
* Two separate faults produced that line. The interpolated expression
|
|
15
|
+
* `-(cameraX || ''` was missing its closing paren, and the "re-close the CSS
|
|
16
|
+
* function" step counted parentheses across the WHOLE string — including the
|
|
17
|
+
* ones inside `${…}` — decided one was missing, and appended `px)` to the end,
|
|
18
|
+
* which could never help because the imbalance was inside the interpolation.
|
|
19
|
+
*
|
|
20
|
+
* One bad binding in one style property must never cost a project its build.
|
|
21
|
+
* These helpers make the imbalance repairable where it actually is, and let the
|
|
22
|
+
* caller degrade a single value instead of aborting.
|
|
23
|
+
*/
|
|
24
|
+
export interface ExpressionScan {
|
|
25
|
+
/** Openers still waiting for their closer, outermost first. */
|
|
26
|
+
unclosed: string[];
|
|
27
|
+
/** Closers that never had a matching opener. */
|
|
28
|
+
strayCloserCount: number;
|
|
29
|
+
/** The quote character still open at the end of the scan, if any. */
|
|
30
|
+
unterminatedQuote: string | null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Single left-to-right pass over an expression, quote and escape aware.
|
|
34
|
+
* Characters inside a string literal never affect nesting.
|
|
35
|
+
*/
|
|
36
|
+
export declare const scanExpression: (expression: string) => ExpressionScan;
|
|
37
|
+
/** True when every quote and bracket closes and no closer is stray. */
|
|
38
|
+
export declare const isBalancedExpression: (expression: string) => boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Close an expression that ends mid-quote or mid-bracket:
|
|
41
|
+
* `-(cameraX || ''` → `-(cameraX || '')`.
|
|
42
|
+
*
|
|
43
|
+
* Returns the expression unchanged when it is already balanced, and when the
|
|
44
|
+
* imbalance is a STRAY CLOSER — appending cannot fix a missing opener, and
|
|
45
|
+
* inventing one would be a guess.
|
|
46
|
+
*/
|
|
47
|
+
export declare const balanceExpression: (expression: string) => string;
|
|
48
|
+
/**
|
|
49
|
+
* Parenthesis balance of the STATIC parts of a template string — everything
|
|
50
|
+
* outside `${…}`.
|
|
51
|
+
*
|
|
52
|
+
* This is the number the "re-close the CSS function" step needs. Counting over
|
|
53
|
+
* the whole string mixes in the expressions' own parentheses, so an imbalance
|
|
54
|
+
* INSIDE an interpolation reads as a missing close on the CSS function and the
|
|
55
|
+
* step appends a unit and a `)` that belong nowhere.
|
|
56
|
+
*/
|
|
57
|
+
export declare const countUnclosedStaticParens: (templateStr: string) => number;
|
|
58
|
+
//# sourceMappingURL=template-expression-balance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-expression-balance.d.ts","sourceRoot":"","sources":["../../../src/utils/template-expression-balance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAYH,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,gDAAgD;IAChD,gBAAgB,EAAE,MAAM,CAAA;IACxB,qEAAqE;IACrE,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,eAAgB,MAAM,KAAG,cAyCnD,CAAA;AAED,uEAAuE;AACvE,eAAO,MAAM,oBAAoB,eAAgB,MAAM,KAAG,OAKzD,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,eAAgB,MAAM,KAAG,MAYtD,CAAA;AAQD;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,gBAAiB,MAAM,KAAG,MAkB/D,CAAA"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delimiter balancing for `{{ … }}` binding expressions.
|
|
3
|
+
*
|
|
4
|
+
* THE DEFECT THIS EXISTS FOR. `parseStringWithTemplateExpressions` converted a
|
|
5
|
+
* UIDL string into a template literal and then handed the result straight to
|
|
6
|
+
* Babel. When the binding inside was unbalanced the produced source did not
|
|
7
|
+
* parse, `parse()` threw, and — because the inline-style caller has no
|
|
8
|
+
* try/catch — the SyntaxError escaped all the way out and killed the ENTIRE
|
|
9
|
+
* project build:
|
|
10
|
+
*
|
|
11
|
+
* const x = `translateX(${-(cameraX || ''}px) }px)`
|
|
12
|
+
* ^ Unexpected token, expected ","
|
|
13
|
+
*
|
|
14
|
+
* Two separate faults produced that line. The interpolated expression
|
|
15
|
+
* `-(cameraX || ''` was missing its closing paren, and the "re-close the CSS
|
|
16
|
+
* function" step counted parentheses across the WHOLE string — including the
|
|
17
|
+
* ones inside `${…}` — decided one was missing, and appended `px)` to the end,
|
|
18
|
+
* which could never help because the imbalance was inside the interpolation.
|
|
19
|
+
*
|
|
20
|
+
* One bad binding in one style property must never cost a project its build.
|
|
21
|
+
* These helpers make the imbalance repairable where it actually is, and let the
|
|
22
|
+
* caller degrade a single value instead of aborting.
|
|
23
|
+
*/
|
|
24
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
25
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
26
|
+
if (ar || !(i in from)) {
|
|
27
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
28
|
+
ar[i] = from[i];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
32
|
+
};
|
|
33
|
+
/** Closing delimiter for each opener that nests inside an expression. */
|
|
34
|
+
var CLOSER_FOR_OPENER = {
|
|
35
|
+
'(': ')',
|
|
36
|
+
'[': ']',
|
|
37
|
+
'{': '}',
|
|
38
|
+
};
|
|
39
|
+
var CLOSERS = new Set(Object.values(CLOSER_FOR_OPENER));
|
|
40
|
+
var QUOTES = new Set(["'", '"', '`']);
|
|
41
|
+
/**
|
|
42
|
+
* Single left-to-right pass over an expression, quote and escape aware.
|
|
43
|
+
* Characters inside a string literal never affect nesting.
|
|
44
|
+
*/
|
|
45
|
+
export var scanExpression = function (expression) {
|
|
46
|
+
var unclosed = [];
|
|
47
|
+
var strayCloserCount = 0;
|
|
48
|
+
var quote = null;
|
|
49
|
+
for (var index = 0; index < expression.length; index++) {
|
|
50
|
+
var char = expression[index];
|
|
51
|
+
if (char === '\\') {
|
|
52
|
+
index++;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (quote !== null) {
|
|
56
|
+
if (char === quote) {
|
|
57
|
+
quote = null;
|
|
58
|
+
}
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (QUOTES.has(char)) {
|
|
62
|
+
quote = char;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (CLOSER_FOR_OPENER[char]) {
|
|
66
|
+
unclosed.push(char);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (CLOSERS.has(char)) {
|
|
70
|
+
var expected = unclosed.length > 0 ? CLOSER_FOR_OPENER[unclosed[unclosed.length - 1]] : null;
|
|
71
|
+
if (expected === char) {
|
|
72
|
+
unclosed.pop();
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
strayCloserCount++;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { unclosed: unclosed, strayCloserCount: strayCloserCount, unterminatedQuote: quote };
|
|
80
|
+
};
|
|
81
|
+
/** True when every quote and bracket closes and no closer is stray. */
|
|
82
|
+
export var isBalancedExpression = function (expression) {
|
|
83
|
+
var scan = scanExpression(expression);
|
|
84
|
+
return (scan.unclosed.length === 0 && scan.strayCloserCount === 0 && scan.unterminatedQuote === null);
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Close an expression that ends mid-quote or mid-bracket:
|
|
88
|
+
* `-(cameraX || ''` → `-(cameraX || '')`.
|
|
89
|
+
*
|
|
90
|
+
* Returns the expression unchanged when it is already balanced, and when the
|
|
91
|
+
* imbalance is a STRAY CLOSER — appending cannot fix a missing opener, and
|
|
92
|
+
* inventing one would be a guess.
|
|
93
|
+
*/
|
|
94
|
+
export var balanceExpression = function (expression) {
|
|
95
|
+
var scan = scanExpression(expression);
|
|
96
|
+
if (scan.strayCloserCount > 0) {
|
|
97
|
+
return expression;
|
|
98
|
+
}
|
|
99
|
+
if (scan.unclosed.length === 0 && scan.unterminatedQuote === null) {
|
|
100
|
+
return expression;
|
|
101
|
+
}
|
|
102
|
+
var suffix = __spreadArray([scan.unterminatedQuote || ''], unclosedInReverse(scan.unclosed), true).join('');
|
|
103
|
+
return expression + suffix;
|
|
104
|
+
};
|
|
105
|
+
var unclosedInReverse = function (unclosed) {
|
|
106
|
+
return unclosed
|
|
107
|
+
.slice()
|
|
108
|
+
.reverse()
|
|
109
|
+
.map(function (opener) { return CLOSER_FOR_OPENER[opener]; });
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Parenthesis balance of the STATIC parts of a template string — everything
|
|
113
|
+
* outside `${…}`.
|
|
114
|
+
*
|
|
115
|
+
* This is the number the "re-close the CSS function" step needs. Counting over
|
|
116
|
+
* the whole string mixes in the expressions' own parentheses, so an imbalance
|
|
117
|
+
* INSIDE an interpolation reads as a missing close on the CSS function and the
|
|
118
|
+
* step appends a unit and a `)` that belong nowhere.
|
|
119
|
+
*/
|
|
120
|
+
export var countUnclosedStaticParens = function (templateStr) {
|
|
121
|
+
var depth = 0;
|
|
122
|
+
var index = 0;
|
|
123
|
+
while (index < templateStr.length) {
|
|
124
|
+
if (templateStr[index] === '$' && templateStr[index + 1] === '{') {
|
|
125
|
+
index = skipInterpolation(templateStr, index + 2);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (templateStr[index] === '(') {
|
|
129
|
+
depth++;
|
|
130
|
+
}
|
|
131
|
+
else if (templateStr[index] === ')') {
|
|
132
|
+
depth--;
|
|
133
|
+
}
|
|
134
|
+
index++;
|
|
135
|
+
}
|
|
136
|
+
return depth > 0 ? depth : 0;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Index just past the `}` that closes an interpolation opened at `start`.
|
|
140
|
+
* Tracks nested braces and string literals so `${ {a:'}'} }` is skipped whole.
|
|
141
|
+
* An unterminated interpolation consumes the rest of the string.
|
|
142
|
+
*/
|
|
143
|
+
var skipInterpolation = function (templateStr, start) {
|
|
144
|
+
var depth = 1;
|
|
145
|
+
var quote = null;
|
|
146
|
+
for (var index = start; index < templateStr.length; index++) {
|
|
147
|
+
var char = templateStr[index];
|
|
148
|
+
if (char === '\\') {
|
|
149
|
+
index++;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (quote !== null) {
|
|
153
|
+
if (char === quote) {
|
|
154
|
+
quote = null;
|
|
155
|
+
}
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (QUOTES.has(char)) {
|
|
159
|
+
quote = char;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (char === '{') {
|
|
163
|
+
depth++;
|
|
164
|
+
}
|
|
165
|
+
else if (char === '}') {
|
|
166
|
+
depth--;
|
|
167
|
+
if (depth === 0) {
|
|
168
|
+
return index + 1;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return templateStr.length;
|
|
173
|
+
};
|
|
174
|
+
//# sourceMappingURL=template-expression-balance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-expression-balance.js","sourceRoot":"","sources":["../../../src/utils/template-expression-balance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;;;;;;;;AAEH,yEAAyE;AACzE,IAAM,iBAAiB,GAA2B;IAChD,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;CACT,CAAA;AAED,IAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAA;AACzD,IAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;AAWvC;;;GAGG;AACH,MAAM,CAAC,IAAM,cAAc,GAAG,UAAC,UAAkB;IAC/C,IAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,IAAI,gBAAgB,GAAG,CAAC,CAAA;IACxB,IAAI,KAAK,GAAkB,IAAI,CAAA;IAE/B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QACtD,IAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;QAE9B,IAAI,IAAI,KAAK,IAAI,EAAE;YACjB,KAAK,EAAE,CAAA;YACP,SAAQ;SACT;QAED,IAAI,KAAK,KAAK,IAAI,EAAE;YAClB,IAAI,IAAI,KAAK,KAAK,EAAE;gBAClB,KAAK,GAAG,IAAI,CAAA;aACb;YACD,SAAQ;SACT;QAED,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YACpB,KAAK,GAAG,IAAI,CAAA;YACZ,SAAQ;SACT;QAED,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE;YAC3B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnB,SAAQ;SACT;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YACrB,IAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;YAC9F,IAAI,QAAQ,KAAK,IAAI,EAAE;gBACrB,QAAQ,CAAC,GAAG,EAAE,CAAA;aACf;iBAAM;gBACL,gBAAgB,EAAE,CAAA;aACnB;SACF;KACF;IAED,OAAO,EAAE,QAAQ,UAAA,EAAE,gBAAgB,kBAAA,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAA;AACjE,CAAC,CAAA;AAED,uEAAuE;AACvE,MAAM,CAAC,IAAM,oBAAoB,GAAG,UAAC,UAAkB;IACrD,IAAM,IAAI,GAAG,cAAc,CAAC,UAAU,CAAC,CAAA;IACvC,OAAO,CACL,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,gBAAgB,KAAK,CAAC,IAAI,IAAI,CAAC,iBAAiB,KAAK,IAAI,CAC7F,CAAA;AACH,CAAC,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,IAAM,iBAAiB,GAAG,UAAC,UAAkB;IAClD,IAAM,IAAI,GAAG,cAAc,CAAC,UAAU,CAAC,CAAA;IACvC,IAAI,IAAI,CAAC,gBAAgB,GAAG,CAAC,EAAE;QAC7B,OAAO,UAAU,CAAA;KAClB;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,iBAAiB,KAAK,IAAI,EAAE;QACjE,OAAO,UAAU,CAAA;KAClB;IAED,IAAM,MAAM,GAAG,eAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,GAAK,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAE,IAAI,CAAC,EAAE,CAAC,CAAA;IAE3F,OAAO,UAAU,GAAG,MAAM,CAAA;AAC5B,CAAC,CAAA;AAED,IAAM,iBAAiB,GAAG,UAAC,QAAkB;IAC3C,OAAA,QAAQ;SACL,KAAK,EAAE;SACP,OAAO,EAAE;SACT,GAAG,CAAC,UAAC,MAAM,IAAK,OAAA,iBAAiB,CAAC,MAAM,CAAC,EAAzB,CAAyB,CAAC;AAH7C,CAG6C,CAAA;AAE/C;;;;;;;;GAQG;AACH,MAAM,CAAC,IAAM,yBAAyB,GAAG,UAAC,WAAmB;IAC3D,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,IAAI,KAAK,GAAG,CAAC,CAAA;IAEb,OAAO,KAAK,GAAG,WAAW,CAAC,MAAM,EAAE;QACjC,IAAI,WAAW,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,WAAW,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE;YAChE,KAAK,GAAG,iBAAiB,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,CAAC,CAAA;YACjD,SAAQ;SACT;QACD,IAAI,WAAW,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE;YAC9B,KAAK,EAAE,CAAA;SACR;aAAM,IAAI,WAAW,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE;YACrC,KAAK,EAAE,CAAA;SACR;QACD,KAAK,EAAE,CAAA;KACR;IAED,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAC9B,CAAC,CAAA;AAED;;;;GAIG;AACH,IAAM,iBAAiB,GAAG,UAAC,WAAmB,EAAE,KAAa;IAC3D,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,IAAI,KAAK,GAAkB,IAAI,CAAA;IAE/B,KAAK,IAAI,KAAK,GAAG,KAAK,EAAE,KAAK,GAAG,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QAC3D,IAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;QAE/B,IAAI,IAAI,KAAK,IAAI,EAAE;YACjB,KAAK,EAAE,CAAA;YACP,SAAQ;SACT;QAED,IAAI,KAAK,KAAK,IAAI,EAAE;YAClB,IAAI,IAAI,KAAK,KAAK,EAAE;gBAClB,KAAK,GAAG,IAAI,CAAA;aACb;YACD,SAAQ;SACT;QAED,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YACpB,KAAK,GAAG,IAAI,CAAA;YACZ,SAAQ;SACT;QAED,IAAI,IAAI,KAAK,GAAG,EAAE;YAChB,KAAK,EAAE,CAAA;SACR;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE;YACvB,KAAK,EAAE,CAAA;YACP,IAAI,KAAK,KAAK,CAAC,EAAE;gBACf,OAAO,KAAK,GAAG,CAAC,CAAA;aACjB;SACF;KACF;IAED,OAAO,WAAW,CAAC,MAAM,CAAA;AAC3B,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teleporthq/teleport-plugin-common",
|
|
3
|
-
"version": "0.43.
|
|
3
|
+
"version": "0.43.48",
|
|
4
4
|
"description": "Common building and modelating functions for ASTs and HASTs",
|
|
5
5
|
"author": "teleportHQ",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"@babel/core": "^7.5.5",
|
|
28
28
|
"@babel/preset-react": "^7.22.5",
|
|
29
29
|
"@babel/types": "^7.5.5",
|
|
30
|
-
"@teleporthq/teleport-shared": "^0.43.
|
|
31
|
-
"@teleporthq/teleport-types": "^0.43.
|
|
30
|
+
"@teleporthq/teleport-shared": "^0.43.48",
|
|
31
|
+
"@teleporthq/teleport-types": "^0.43.47",
|
|
32
32
|
"jss": "^10.0.0",
|
|
33
33
|
"jss-preset-default": "^10.0.0"
|
|
34
34
|
},
|
|
35
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "6eac138670383e733c2b6e5e194da0315bac6a7c"
|
|
36
36
|
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
convertValueToLiteral,
|
|
7
7
|
getExpressionFromUIDLExpressionNode,
|
|
8
8
|
} from '../../utils/ast-utils'
|
|
9
|
-
import { StringUtils, UIDLUtils } from '@teleporthq/teleport-shared'
|
|
9
|
+
import { JSIdentifiers, StringUtils, UIDLUtils } from '@teleporthq/teleport-shared'
|
|
10
10
|
import {
|
|
11
11
|
UIDLPropDefinition,
|
|
12
12
|
UIDLAttributeValue,
|
|
@@ -261,10 +261,14 @@ const createPropCallStatement = (
|
|
|
261
261
|
const prefix = options.dynamicReferencePrefixMap.prop
|
|
262
262
|
? options.dynamicReferencePrefixMap.prop + '.'
|
|
263
263
|
: ''
|
|
264
|
+
// Un-prefixed the prop name is called as a bare binding, so it must be
|
|
265
|
+
// identifier-safe; prefixed it is `props.<name>`, where the UIDL spelling is
|
|
266
|
+
// both legal and load-bearing.
|
|
267
|
+
const calleeName = prefix
|
|
268
|
+
? prefix + propFunctionKey
|
|
269
|
+
: JSIdentifiers.createSafeJSIdentifier(propFunctionKey)
|
|
264
270
|
return t.expressionStatement(
|
|
265
|
-
t.callExpression(t.identifier(
|
|
266
|
-
...args.map((arg) => convertValueToLiteral(arg)),
|
|
267
|
-
])
|
|
271
|
+
t.callExpression(t.identifier(calleeName), [...args.map((arg) => convertValueToLiteral(arg))])
|
|
268
272
|
)
|
|
269
273
|
}
|
|
270
274
|
|
|
@@ -310,6 +314,12 @@ export const createStateChangeStatement = (
|
|
|
310
314
|
const statePrefix = options.dynamicReferencePrefixMap.state
|
|
311
315
|
? options.dynamicReferencePrefixMap.state + '.'
|
|
312
316
|
: ''
|
|
317
|
+
// Reading/writing the state through a prefix (`this.class`) is a member
|
|
318
|
+
// access and keeps the UIDL spelling; without one the name IS the binding
|
|
319
|
+
// and has to match what `createStateHookAST` declared.
|
|
320
|
+
const stateReadName = statePrefix
|
|
321
|
+
? statePrefix + stateKey
|
|
322
|
+
: JSIdentifiers.createSafeJSIdentifier(stateKey)
|
|
313
323
|
|
|
314
324
|
const declaredType = stateDefinition.type
|
|
315
325
|
const newState = eventHandlerStatement.newState
|
|
@@ -326,7 +336,7 @@ export const createStateChangeStatement = (
|
|
|
326
336
|
)
|
|
327
337
|
return null
|
|
328
338
|
}
|
|
329
|
-
newStateValue = t.unaryExpression('!', t.identifier(
|
|
339
|
+
newStateValue = t.unaryExpression('!', t.identifier(stateReadName))
|
|
330
340
|
} else if (typeof newState === 'object' && newState !== null) {
|
|
331
341
|
const obj = newState as
|
|
332
342
|
| UIDLDynamicReference
|
|
@@ -473,7 +483,7 @@ export const createStateChangeStatement = (
|
|
|
473
483
|
return null
|
|
474
484
|
}
|
|
475
485
|
return t.expressionStatement(
|
|
476
|
-
t.assignmentExpression('=', t.identifier(
|
|
486
|
+
t.assignmentExpression('=', t.identifier(stateReadName), newStateValue)
|
|
477
487
|
)
|
|
478
488
|
}
|
|
479
489
|
}
|
|
@@ -540,7 +550,12 @@ export const resolveAndRegisterGlobalStateSource = (
|
|
|
540
550
|
for (const def of Object.values(definitions)) {
|
|
541
551
|
if (def.id === id) {
|
|
542
552
|
params.globalStateReferences.push({ id: def.id, name: def.name })
|
|
543
|
-
|
|
553
|
+
// The rewritten source is embedded as code, so the placeholder becomes
|
|
554
|
+
// the LOCAL binding — the sanitised name the destructuring declares.
|
|
555
|
+
return original.replace(
|
|
556
|
+
LEGACY_GLOBAL_STATE_RE,
|
|
557
|
+
JSIdentifiers.createSafeJSIdentifier(def.name)
|
|
558
|
+
)
|
|
544
559
|
}
|
|
545
560
|
}
|
|
546
561
|
// Legacy prefix found but no matching definition (orphaned reference).
|
|
@@ -568,7 +583,11 @@ export const createGlobalStateExpression = (
|
|
|
568
583
|
definitions?: Record<string, UIDLGlobalStateDefinition>,
|
|
569
584
|
t = types
|
|
570
585
|
): types.Identifier | types.OptionalMemberExpression => {
|
|
571
|
-
|
|
586
|
+
// The global-state name is destructured out of `useGlobalState()` as a local
|
|
587
|
+
// binding, so it goes through the same sanitiser the destructuring site uses.
|
|
588
|
+
const name = JSIdentifiers.createSafeJSIdentifier(
|
|
589
|
+
resolveGlobalStateName(ref.content.id, definitions)
|
|
590
|
+
)
|
|
572
591
|
const refPath = ref.content.refPath || []
|
|
573
592
|
|
|
574
593
|
if (refPath.length === 0) {
|
|
@@ -765,8 +784,12 @@ const createDynamicValueExpressionRaw = (
|
|
|
765
784
|
const prefix =
|
|
766
785
|
options.dynamicReferencePrefixMap[referenceType as 'prop' | 'state' | 'local'] || ''
|
|
767
786
|
|
|
787
|
+
// With no prefix the id IS the binding (React hooks: `class`), so it has to
|
|
788
|
+
// be sanitised exactly the way the declaration was. With a prefix it is a
|
|
789
|
+
// MEMBER (`props.class`, `this.class`), where a reserved word is perfectly
|
|
790
|
+
// legal and renaming it would point at a property that does not exist.
|
|
768
791
|
return prefix === ''
|
|
769
|
-
? t.identifier(idWithPath)
|
|
792
|
+
? t.identifier(JSIdentifiers.createSafeJSIdentifierPath(idWithPath))
|
|
770
793
|
: t.memberExpression(t.identifier(prefix), t.identifier(idWithPath))
|
|
771
794
|
}
|
|
772
795
|
|
|
@@ -1038,12 +1061,15 @@ export const createBinaryExpression = (
|
|
|
1038
1061
|
t = types
|
|
1039
1062
|
) => {
|
|
1040
1063
|
const { operand, operation, containsField } = condition
|
|
1064
|
+
// Same rule as `createDynamicValueExpression`: an un-prefixed key is the
|
|
1065
|
+
// binding itself and must be identifier-safe; a prefixed one is a member
|
|
1066
|
+
// access that has to keep the UIDL's original spelling.
|
|
1041
1067
|
const identifier = conditionalIdentifier.prefix
|
|
1042
1068
|
? t.memberExpression(
|
|
1043
1069
|
t.identifier(conditionalIdentifier.prefix),
|
|
1044
1070
|
t.identifier(conditionalIdentifier.key)
|
|
1045
1071
|
)
|
|
1046
|
-
: t.identifier(conditionalIdentifier.key)
|
|
1072
|
+
: t.identifier(JSIdentifiers.createSafeJSIdentifierPath(conditionalIdentifier.key))
|
|
1047
1073
|
|
|
1048
1074
|
// Array/Object operators
|
|
1049
1075
|
if (operation === 'isEmpty') {
|
package/src/utils/ast-utils.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as types from '@babel/types'
|
|
2
2
|
import { parse } from '@babel/core'
|
|
3
3
|
import ParsedASTNode from './parsed-ast'
|
|
4
|
-
import { StringUtils, UIDLUtils } from '@teleporthq/teleport-shared'
|
|
4
|
+
import { JSIdentifiers, StringUtils, UIDLUtils } from '@teleporthq/teleport-shared'
|
|
5
5
|
import {
|
|
6
6
|
UIDLStateDefinition,
|
|
7
7
|
UIDLPropDefinition,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from '@teleporthq/teleport-types'
|
|
17
17
|
import babelPresetReact from '@babel/preset-react'
|
|
18
18
|
import { UnaryOperation, BinaryOperator } from './types'
|
|
19
|
+
import { balanceExpression, countUnclosedStaticParens } from './template-expression-balance'
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Converts HTML attribute names to React/JSX camelCase format
|
|
@@ -140,9 +141,14 @@ export const addDynamicAttributeToJSXTag = (
|
|
|
140
141
|
t = types
|
|
141
142
|
) => {
|
|
142
143
|
const reactName = convertToReactAttributeName(name)
|
|
144
|
+
// Same rule as `createDynamicValueExpression`: with no prefix the value IS the
|
|
145
|
+
// binding (React hooks state), so it must match the sanitised name
|
|
146
|
+
// `createStateHookAST` declared — `value={class}` does not parse. With a
|
|
147
|
+
// prefix it is `props.class` / `this.class`, where the UIDL spelling is legal
|
|
148
|
+
// AND load-bearing, so it is left alone.
|
|
143
149
|
const content =
|
|
144
150
|
prefix === ''
|
|
145
|
-
? t.identifier(value)
|
|
151
|
+
? t.identifier(JSIdentifiers.createSafeJSIdentifierPath(value))
|
|
146
152
|
: t.memberExpression(t.identifier(prefix), t.identifier(value))
|
|
147
153
|
|
|
148
154
|
jsxASTNode.openingElement.attributes.push(
|
|
@@ -354,9 +360,15 @@ export const parseStringWithTemplateExpressions = (str: string): types.TemplateL
|
|
|
354
360
|
const normalized = str.replace(/state\.(\w+)/g, '$1')
|
|
355
361
|
|
|
356
362
|
// Step 2: Convert well-formed {{ expr }} to ${expr}
|
|
363
|
+
//
|
|
364
|
+
// The expression is BALANCED on the way in. A binding that lost a closing
|
|
365
|
+
// paren upstream (`-(cameraX || ''`) produces source Babel cannot parse, and
|
|
366
|
+
// no amount of patching the static text around it can help — the repair has
|
|
367
|
+
// to happen inside the interpolation, which is the only place the bracket is
|
|
368
|
+
// actually missing.
|
|
357
369
|
let templateStr = normalized.replace(
|
|
358
370
|
/\{\{\s*(.+?)\s*\}\}/g,
|
|
359
|
-
(_, expr: string) => '${' + expr.trim() + '}'
|
|
371
|
+
(_, expr: string) => '${' + balanceExpression(expr.trim()) + '}'
|
|
360
372
|
)
|
|
361
373
|
|
|
362
374
|
// Step 3: Handle unclosed {{ expr (no closing }})
|
|
@@ -364,16 +376,20 @@ export const parseStringWithTemplateExpressions = (str: string): types.TemplateL
|
|
|
364
376
|
if (/\{\{/.test(templateStr)) {
|
|
365
377
|
templateStr = templateStr.replace(
|
|
366
378
|
/\{\{\s*(.+?)$/gm,
|
|
367
|
-
(_, expr: string) => '${' + expr.trim() + '}'
|
|
379
|
+
(_, expr: string) => '${' + balanceExpression(expr.trim()) + '}'
|
|
368
380
|
)
|
|
369
381
|
}
|
|
370
382
|
|
|
371
383
|
// Step 4: Detect and fix incomplete CSS function calls
|
|
372
384
|
// If the original string contained a CSS function like translateX(...) or translate(...)
|
|
373
385
|
// but the template expression consumed the closing, we need to re-close it.
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
386
|
+
//
|
|
387
|
+
// Counted over the STATIC text only. Including the parentheses inside `${…}`
|
|
388
|
+
// made an imbalance in the expression look like an unclosed CSS function, so
|
|
389
|
+
// this step appended a unit and a `)` to the end of a string whose real fault
|
|
390
|
+
// was several characters earlier and inside the interpolation.
|
|
391
|
+
const missingStaticCloses = countUnclosedStaticParens(templateStr)
|
|
392
|
+
if (missingStaticCloses > 0) {
|
|
377
393
|
// Determine the CSS unit by:
|
|
378
394
|
// 1. Looking for existing units already in the string (e.g. "translate(${x}px, ${y" → px)
|
|
379
395
|
// 2. Inferring from the CSS function name
|
|
@@ -393,22 +409,53 @@ export const parseStringWithTemplateExpressions = (str: string): types.TemplateL
|
|
|
393
409
|
}
|
|
394
410
|
}
|
|
395
411
|
|
|
396
|
-
|
|
397
|
-
templateStr += unit + ')'.repeat(missingCloses)
|
|
412
|
+
templateStr += unit + ')'.repeat(missingStaticCloses)
|
|
398
413
|
}
|
|
399
414
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
415
|
+
// Step 5: Parse — and NEVER let a single malformed binding abort the build.
|
|
416
|
+
//
|
|
417
|
+
// The inline-style caller has no error handling of its own, so an
|
|
418
|
+
// unparseable template used to escape as a raw Babel SyntaxError and take the
|
|
419
|
+
// whole project generation down with it. A UIDL can always carry a binding
|
|
420
|
+
// this module cannot rescue (hand-edited, produced by an older pipeline, or
|
|
421
|
+
// broken in a way `balanceExpression` refuses to guess at), and the right
|
|
422
|
+
// answer is to degrade that ONE value: emit the original text as a plain
|
|
423
|
+
// string so the property still renders and the other 99 pages still build.
|
|
424
|
+
try {
|
|
425
|
+
const ast = parse('const x = `' + templateStr + '`', {
|
|
426
|
+
sourceType: 'module',
|
|
427
|
+
})
|
|
403
428
|
|
|
404
|
-
|
|
405
|
-
|
|
429
|
+
if (ast && 'program' in ast) {
|
|
430
|
+
const decl = ast.program.body[0] as types.VariableDeclaration
|
|
431
|
+
return decl.declarations[0].init as types.TemplateLiteral
|
|
432
|
+
}
|
|
433
|
+
} catch {
|
|
434
|
+
// Fall through to the static fallback below.
|
|
406
435
|
}
|
|
407
436
|
|
|
408
|
-
|
|
409
|
-
return decl.declarations[0].init as types.TemplateLiteral
|
|
437
|
+
return staticTemplateLiteral(stripTemplateExpressions(str))
|
|
410
438
|
}
|
|
411
439
|
|
|
440
|
+
/**
|
|
441
|
+
* Drop every `{{ … }}` binding from a string, keeping any `'literal'` fallback
|
|
442
|
+
* it declared. `translateX({{ -(x || 0) }}px)` → `translateX(px)` is useless as
|
|
443
|
+
* a style value, but `{{ name || 'Guest' }}` → `Guest` keeps the text the
|
|
444
|
+
* author intended. Used only when the expression could not be parsed at all.
|
|
445
|
+
*/
|
|
446
|
+
const stripTemplateExpressions = (value: string): string =>
|
|
447
|
+
value.replace(/\{\{\s*([\s\S]*?)\s*\}\}/g, (_, expr: string) => {
|
|
448
|
+
const literalFallback = /\|\|\s*(['"])([\s\S]*?)\1\s*$/.exec(expr)
|
|
449
|
+
return literalFallback ? literalFallback[2] : ''
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
/** A TemplateLiteral with no interpolations, holding `value` verbatim. */
|
|
453
|
+
const staticTemplateLiteral = (value: string): types.TemplateLiteral =>
|
|
454
|
+
types.templateLiteral(
|
|
455
|
+
[types.templateElement({ raw: value.replace(/[\\`]/g, '\\$&'), cooked: value }, true)],
|
|
456
|
+
[]
|
|
457
|
+
)
|
|
458
|
+
|
|
412
459
|
const REACT_BOOLEAN_DOM_PROPS = new Set([
|
|
413
460
|
'disabled',
|
|
414
461
|
'required',
|
|
@@ -931,7 +978,11 @@ export const createStateHookAST = (
|
|
|
931
978
|
return t.variableDeclaration('const', [
|
|
932
979
|
t.variableDeclarator(
|
|
933
980
|
t.arrayPattern([
|
|
934
|
-
|
|
981
|
+
// The state NAME comes from the UIDL and may be a reserved word (a
|
|
982
|
+
// character sheet has a column called `class`), which is fatal in
|
|
983
|
+
// binding position. Reads go through the same sanitiser, so the
|
|
984
|
+
// declaration and every reference stay in sync.
|
|
985
|
+
t.identifier(JSIdentifiers.createSafeJSIdentifier(stateKey)),
|
|
935
986
|
t.identifier(StringUtils.createStateStoringFunction(stateKey)),
|
|
936
987
|
]),
|
|
937
988
|
t.callExpression(t.identifier('useState'), [useStateArgument])
|
package/src/utils/route-utils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { UIDLWorkflows } from '@teleporthq/teleport-types'
|
|
2
|
+
import { RoutePaths } from '@teleporthq/teleport-shared'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* True when this UIDL component's output route contains a Next.js dynamic
|
|
@@ -13,6 +14,14 @@ export const isDynamicRoute = (uidl: {
|
|
|
13
14
|
)
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Reading a route TEMPLATE (`/event-details/[id]`) rather than a URL. Defined in
|
|
19
|
+
* teleport-shared because the navlink resolver needs the same two functions and
|
|
20
|
+
* lives in a package that does not depend on this one; re-exported here so
|
|
21
|
+
* `RouteUtils` stays the single import for route questions in the plugins.
|
|
22
|
+
*/
|
|
23
|
+
export const { pathHasDynamicSegment, parseDynamicPathSegments } = RoutePaths
|
|
24
|
+
|
|
16
25
|
const MUTATION_NODE_TYPES = new Set(['data-create-item', 'data-update-item'])
|
|
17
26
|
|
|
18
27
|
/**
|