@cedarjs/structure 9.0.0-canary.1784 → 9.0.0-canary.3124
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/README.md +1 -1
- package/dist/errors.d.ts +2 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +10 -15
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -67
- package/dist/index.js.map +1 -0
- package/dist/model/RWCell.d.ts +4 -4
- package/dist/model/RWCell.d.ts.map +1 -1
- package/dist/model/RWCell.js +111 -103
- package/dist/model/RWCell.js.map +1 -0
- package/dist/model/RWComponent.d.ts +2 -2
- package/dist/model/RWComponent.d.ts.map +1 -1
- package/dist/model/RWComponent.js +46 -41
- package/dist/model/RWComponent.js.map +1 -0
- package/dist/model/RWEnvHelper.d.ts +4 -4
- package/dist/model/RWEnvHelper.d.ts.map +1 -1
- package/dist/model/RWEnvHelper.js +233 -205
- package/dist/model/RWEnvHelper.js.map +1 -0
- package/dist/model/RWFunction.d.ts +2 -2
- package/dist/model/RWFunction.d.ts.map +1 -1
- package/dist/model/RWFunction.js +10 -15
- package/dist/model/RWFunction.js.map +1 -0
- package/dist/model/RWLayout.d.ts +2 -2
- package/dist/model/RWLayout.d.ts.map +1 -1
- package/dist/model/RWLayout.js +10 -15
- package/dist/model/RWLayout.js.map +1 -0
- package/dist/model/RWPage.d.ts +3 -3
- package/dist/model/RWPage.d.ts.map +1 -1
- package/dist/model/RWPage.js +61 -57
- package/dist/model/RWPage.js.map +1 -0
- package/dist/model/RWProject.d.ts +22 -18
- package/dist/model/RWProject.d.ts.map +1 -1
- package/dist/model/RWProject.js +257 -164
- package/dist/model/RWProject.js.map +1 -0
- package/dist/model/RWRoute.d.ts +32 -6
- package/dist/model/RWRoute.d.ts.map +1 -1
- package/dist/model/RWRoute.js +424 -260
- package/dist/model/RWRoute.js.map +1 -0
- package/dist/model/RWRouter.d.ts +4 -4
- package/dist/model/RWRouter.d.ts.map +1 -1
- package/dist/model/RWRouter.js +130 -126
- package/dist/model/RWRouter.js.map +1 -0
- package/dist/model/RWSDL.d.ts +5 -5
- package/dist/model/RWSDL.d.ts.map +1 -1
- package/dist/model/RWSDL.js +96 -84
- package/dist/model/RWSDL.js.map +1 -0
- package/dist/model/RWSDLField.d.ts +6 -6
- package/dist/model/RWSDLField.d.ts.map +1 -1
- package/dist/model/RWSDLField.js +79 -81
- package/dist/model/RWSDLField.js.map +1 -0
- package/dist/model/RWService.d.ts +4 -4
- package/dist/model/RWService.d.ts.map +1 -1
- package/dist/model/RWService.js +76 -76
- package/dist/model/RWService.js.map +1 -0
- package/dist/model/RWServiceFunction.d.ts +4 -4
- package/dist/model/RWServiceFunction.d.ts.map +1 -1
- package/dist/model/RWServiceFunction.js +95 -97
- package/dist/model/RWServiceFunction.js.map +1 -0
- package/dist/model/RWTOML.d.ts +3 -3
- package/dist/model/RWTOML.d.ts.map +1 -1
- package/dist/model/RWTOML.js +53 -55
- package/dist/model/RWTOML.js.map +1 -0
- package/dist/model/index.d.ts +2 -2
- package/dist/model/index.d.ts.map +1 -1
- package/dist/model/index.js +3 -20
- package/dist/model/index.js.map +1 -0
- package/dist/model/util/pageMutationUsage.d.ts +18 -0
- package/dist/model/util/pageMutationUsage.d.ts.map +1 -0
- package/dist/model/util/pageMutationUsage.js +256 -0
- package/dist/model/util/pageMutationUsage.js.map +1 -0
- package/dist/model/util/process_env.js +44 -62
- package/dist/model/util/process_env.js.map +1 -0
- package/dist/nodes.d.ts +2 -2
- package/dist/nodes.d.ts.map +1 -1
- package/dist/nodes.js +171 -164
- package/dist/nodes.js.map +1 -0
- package/dist/util.js +23 -33
- package/dist/util.js.map +1 -0
- package/dist/x/Array.d.ts.map +1 -1
- package/dist/x/Array.js +15 -25
- package/dist/x/Array.js.map +1 -0
- package/dist/x/Location.d.ts +1 -1
- package/dist/x/Location.d.ts.map +1 -1
- package/dist/x/Location.js +11 -17
- package/dist/x/Location.js.map +1 -0
- package/dist/x/Position.js +18 -29
- package/dist/x/Position.js.map +1 -0
- package/dist/x/Range.d.ts +1 -1
- package/dist/x/Range.d.ts.map +1 -1
- package/dist/x/Range.js +17 -22
- package/dist/x/Range.js.map +1 -0
- package/dist/x/URL.js +59 -75
- package/dist/x/URL.js.map +1 -0
- package/dist/x/child_process.d.ts +1 -1
- package/dist/x/child_process.d.ts.map +1 -1
- package/dist/x/child_process.js +35 -49
- package/dist/x/child_process.js.map +1 -0
- package/dist/x/decorators.d.ts +2 -2
- package/dist/x/decorators.d.ts.map +1 -1
- package/dist/x/decorators.js +46 -26
- package/dist/x/decorators.js.map +1 -0
- package/dist/x/diagnostics.d.ts +3 -3
- package/dist/x/diagnostics.d.ts.map +1 -1
- package/dist/x/diagnostics.js +163 -259
- package/dist/x/diagnostics.js.map +1 -0
- package/dist/x/path.js +36 -55
- package/dist/x/path.js.map +1 -0
- package/dist/x/prisma.d.ts +2 -2
- package/dist/x/prisma.d.ts.map +1 -1
- package/dist/x/prisma.js +32 -55
- package/dist/x/prisma.js.map +1 -0
- package/dist/x/ts-morph.js +34 -45
- package/dist/x/ts-morph.js.map +1 -0
- package/package.json +46 -22
- package/LICENSE +0 -21
package/dist/model/RWRoute.js
CHANGED
|
@@ -1,290 +1,454 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
var _dec, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _dec0, _dec1, _dec10, _dec11, _dec12, _dec13, _dec14, _dec15, _dec16, _dec17, _class;
|
|
27
|
-
let RWRoute = exports.RWRoute = (_dec = (0, _decorators.lazy)(), _dec2 = (0, _decorators.lazy)(), _dec3 = (0, _decorators.lazy)(), _dec4 = (0, _decorators.lazy)(), _dec5 = (0, _decorators.lazy)(), _dec6 = (0, _decorators.lazy)(), _dec7 = (0, _decorators.lazy)(), _dec8 = (0, _decorators.lazy)(), _dec9 = (0, _decorators.lazy)(), _dec0 = (0, _decorators.lazy)(), _dec1 = (0, _decorators.lazy)(), _dec10 = (0, _decorators.lazy)(), _dec11 = (0, _decorators.lazy)(), _dec12 = (0, _decorators.lazy)(), _dec13 = (0, _decorators.lazy)(), _dec14 = (0, _decorators.lazy)(), _dec15 = (0, _decorators.lazy)(), _dec16 = (0, _decorators.lazy)(), _dec17 = (0, _decorators.lazy)(), _class = class RWRoute extends _nodes.BaseNode {
|
|
28
|
-
constructor(
|
|
29
|
-
/**
|
|
30
|
-
* the <Route> tag
|
|
31
|
-
*/
|
|
32
|
-
jsxNode, parent) {
|
|
33
|
-
super();
|
|
34
|
-
this.jsxNode = jsxNode;
|
|
35
|
-
this.parent = parent;
|
|
36
|
-
}
|
|
37
|
-
get id() {
|
|
38
|
-
// we cannot rely on the "path" attribute of the node
|
|
39
|
-
// it might not be unique (which is an error state, but valid while editing)
|
|
40
|
-
return this.parent.id + ' ' + this.jsxNode.getStart();
|
|
41
|
-
}
|
|
42
|
-
get location() {
|
|
43
|
-
return (0, _diagnostics.LocationLike_toLocation)(this.jsxNode);
|
|
44
|
-
}
|
|
45
|
-
get isPrivate() {
|
|
46
|
-
const tagText = this.jsxNode.getParentIfKind(tsm.SyntaxKind.JsxElement)?.getOpeningElement()?.getTagNameNode()?.getText();
|
|
47
|
-
return tagText === 'Private' || tagText === 'PrivateSet';
|
|
48
|
-
}
|
|
49
|
-
get unauthenticated() {
|
|
50
|
-
if (!this.isPrivate) {
|
|
51
|
-
return undefined;
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import * as tsm from 'ts-morph';
|
|
9
|
+
import { RWError } from '../errors.js';
|
|
10
|
+
import { BaseNode } from '../nodes.js';
|
|
11
|
+
import { validateRoutePath } from '../util.js';
|
|
12
|
+
import { lazy } from '../x/decorators.js';
|
|
13
|
+
import { err, DiagnosticSeverity, LocationLike_toLocation, } from '../x/diagnostics.js';
|
|
14
|
+
import { getMutationFieldsUsedTransitively } from './util/pageMutationUsage.js';
|
|
15
|
+
export class RWRoute extends BaseNode {
|
|
16
|
+
jsxNode;
|
|
17
|
+
parent;
|
|
18
|
+
constructor(
|
|
19
|
+
/**
|
|
20
|
+
* the <Route> tag
|
|
21
|
+
*/
|
|
22
|
+
jsxNode, parent) {
|
|
23
|
+
super();
|
|
24
|
+
this.jsxNode = jsxNode;
|
|
25
|
+
this.parent = parent;
|
|
52
26
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
27
|
+
get id() {
|
|
28
|
+
// we cannot rely on the "path" attribute of the node
|
|
29
|
+
// it might not be unique (which is an error state, but valid while editing)
|
|
30
|
+
return this.parent.id + ' ' + this.jsxNode.getStart();
|
|
56
31
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (tsm.Node.isStringLiteral(init)) {
|
|
60
|
-
return init.getLiteralValue();
|
|
61
|
-
}
|
|
32
|
+
get location() {
|
|
33
|
+
return LocationLike_toLocation(this.jsxNode);
|
|
62
34
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
35
|
+
/**
|
|
36
|
+
* All enclosing `<Private>` / `<PrivateSet>` JSX elements, walking up from
|
|
37
|
+
* this route's `<Route>` tag to (but not including) the `<Router>` tag.
|
|
38
|
+
* Ordered innermost-first, so `privateAncestors[0]` (if present) is the
|
|
39
|
+
* nearest wrapper. A route can be nested inside a plain `<Set>` that is
|
|
40
|
+
* itself inside a `<PrivateSet>`, so we can't just look at the immediate
|
|
41
|
+
* JSX parent.
|
|
42
|
+
*/
|
|
43
|
+
get privateAncestors() {
|
|
44
|
+
const ancestors = [];
|
|
45
|
+
let current = this.jsxNode;
|
|
46
|
+
let parentElement = current.getParentIfKind(tsm.SyntaxKind.JsxElement);
|
|
47
|
+
while (parentElement) {
|
|
48
|
+
const tagName = parentElement
|
|
49
|
+
.getOpeningElement()
|
|
50
|
+
.getTagNameNode()
|
|
51
|
+
.getText();
|
|
52
|
+
// Don't walk past the <Router> tag
|
|
53
|
+
if (tagName === 'Router') {
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
if (tagName === 'Private' || tagName === 'PrivateSet') {
|
|
57
|
+
ancestors.push(parentElement);
|
|
58
|
+
}
|
|
59
|
+
current = parentElement;
|
|
60
|
+
parentElement = current.getParentIfKind(tsm.SyntaxKind.JsxElement);
|
|
61
|
+
}
|
|
62
|
+
return ancestors;
|
|
68
63
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return undefined;
|
|
64
|
+
get isPrivate() {
|
|
65
|
+
return this.privateAncestors.length > 0;
|
|
72
66
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// Check if the string looks like an array with single quotes
|
|
81
|
-
if ((0, _startsWith.default)(literalValue).call(literalValue, '[') && (0, _endsWith.default)(literalValue).call(literalValue, ']')) {
|
|
82
|
-
try {
|
|
83
|
-
// Unescape the string by replacing single quotes with double quotes
|
|
84
|
-
const correctedLiteralValue = literalValue.replace(/'/g, '"');
|
|
85
|
-
// Attempt to parse as JSON array
|
|
86
|
-
const parsedValue = JSON.parse(correctedLiteralValue);
|
|
87
|
-
if ((0, _isArray.default)(parsedValue)) {
|
|
88
|
-
return parsedValue;
|
|
67
|
+
get unauthenticated() {
|
|
68
|
+
// Use the innermost Private/PrivateSet ancestor that carries the
|
|
69
|
+
// attribute
|
|
70
|
+
for (const ancestor of this.privateAncestors) {
|
|
71
|
+
const a = ancestor.getOpeningElement().getAttribute('unauthenticated');
|
|
72
|
+
if (!a) {
|
|
73
|
+
continue;
|
|
89
74
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// If not an array, return the string value
|
|
97
|
-
return literalValue;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Handle JSX expressions with array literals
|
|
101
|
-
if (tsm.Node.isJsxExpression(init)) {
|
|
102
|
-
const expr = init.getExpression();
|
|
103
|
-
if (tsm.Node.isArrayLiteralExpression(expr)) {
|
|
104
|
-
var _context, _context2;
|
|
105
|
-
return (0, _filter.default)(_context = (0, _map.default)(_context2 = expr.getElements()).call(_context2, element => {
|
|
106
|
-
if (tsm.Node.isStringLiteral(element)) {
|
|
107
|
-
return element.getLiteralValue();
|
|
75
|
+
if (tsm.Node.isJsxAttribute(a)) {
|
|
76
|
+
const init = a.getInitializer();
|
|
77
|
+
if (tsm.Node.isStringLiteral(init)) {
|
|
78
|
+
return init.getLiteralValue();
|
|
79
|
+
}
|
|
108
80
|
}
|
|
109
81
|
return undefined;
|
|
110
|
-
})).call(_context, val => val !== undefined);
|
|
111
82
|
}
|
|
112
|
-
|
|
83
|
+
return undefined;
|
|
113
84
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
85
|
+
get roles() {
|
|
86
|
+
// Each Private/PrivateSet wrapper independently guards the route, so the
|
|
87
|
+
// effective requirement is the union of roles across all of them
|
|
88
|
+
const rolesPerAncestor = this.privateAncestors
|
|
89
|
+
.map((ancestor) => this.getRolesAttr(ancestor.getOpeningElement()))
|
|
90
|
+
.filter((val) => val !== undefined);
|
|
91
|
+
if (rolesPerAncestor.length === 0) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
// Preserve today's single-wrapper behavior (and its return shape)
|
|
95
|
+
// exactly when there's only one ancestor with roles
|
|
96
|
+
if (rolesPerAncestor.length === 1) {
|
|
97
|
+
return rolesPerAncestor[0];
|
|
98
|
+
}
|
|
99
|
+
const union = new Set();
|
|
100
|
+
for (const roles of rolesPerAncestor) {
|
|
101
|
+
if (Array.isArray(roles)) {
|
|
102
|
+
roles.forEach((role) => union.add(role));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
union.add(roles);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return [...union];
|
|
120
109
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Reads the `roles` attribute off a `<Private>`/`<PrivateSet>` opening
|
|
112
|
+
* element, handling the string literal, quasi-JSON string
|
|
113
|
+
* (e.g. `"['a','b']"`), and JSX array-literal expression forms.
|
|
114
|
+
*/
|
|
115
|
+
getRolesAttr(openingElement) {
|
|
116
|
+
const a = openingElement.getAttribute('roles');
|
|
117
|
+
if (!a) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
if (tsm.Node.isJsxAttribute(a)) {
|
|
121
|
+
const init = a.getInitializer();
|
|
122
|
+
// Handle string literals
|
|
123
|
+
if (tsm.Node.isStringLiteral(init)) {
|
|
124
|
+
const literalValue = init.getLiteralValue();
|
|
125
|
+
// Check if the string looks like an array with single quotes
|
|
126
|
+
if (literalValue.startsWith('[') && literalValue.endsWith(']')) {
|
|
127
|
+
try {
|
|
128
|
+
// Unescape the string by replacing single quotes with double quotes
|
|
129
|
+
const correctedLiteralValue = literalValue.replace(/'/g, '"');
|
|
130
|
+
// Attempt to parse as JSON array
|
|
131
|
+
const parsedValue = JSON.parse(correctedLiteralValue);
|
|
132
|
+
if (Array.isArray(parsedValue)) {
|
|
133
|
+
return parsedValue;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// If parsing fails, return undefined
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// If not an array, return the string value
|
|
142
|
+
return literalValue;
|
|
143
|
+
}
|
|
144
|
+
// Handle JSX expressions with array literals
|
|
145
|
+
if (tsm.Node.isJsxExpression(init)) {
|
|
146
|
+
const expr = init.getExpression();
|
|
147
|
+
if (tsm.Node.isArrayLiteralExpression(expr)) {
|
|
148
|
+
return expr
|
|
149
|
+
.getElements()
|
|
150
|
+
.map((element) => {
|
|
151
|
+
if (tsm.Node.isStringLiteral(element)) {
|
|
152
|
+
return element.getLiteralValue();
|
|
153
|
+
}
|
|
154
|
+
return undefined;
|
|
155
|
+
})
|
|
156
|
+
.filter((val) => val !== undefined);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return undefined;
|
|
136
161
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const a = this.jsxNode.getAttribute('page');
|
|
144
|
-
if (!a) {
|
|
145
|
-
return undefined;
|
|
162
|
+
get hasParameters() {
|
|
163
|
+
if (!this.path) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
// KLUDGE: we need a good path parsing library here
|
|
167
|
+
return this.path.includes('{');
|
|
146
168
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (tsm.Node.isJsxExpression(init)) {
|
|
150
|
-
const expr = init.getExpression();
|
|
151
|
-
if (tsm.Node.isIdentifier(expr)) {
|
|
152
|
-
return expr;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
169
|
+
get hasPrerender() {
|
|
170
|
+
return this.prerender;
|
|
155
171
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
get path_errorMessage() {
|
|
165
|
-
// TODO: path validation is not strong enough
|
|
166
|
-
if (typeof this.path === 'undefined') {
|
|
167
|
-
return undefined;
|
|
172
|
+
/**
|
|
173
|
+
* The associated Redwood Page node, if any
|
|
174
|
+
*/
|
|
175
|
+
get page() {
|
|
176
|
+
if (!this.page_identifier_str) {
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
return this.parent.parent.pages.find((p) => p.constName === this.page_identifier_str);
|
|
168
180
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
181
|
+
/**
|
|
182
|
+
* <Route path="" page={THIS_IDENTIFIER}/>
|
|
183
|
+
*/
|
|
184
|
+
get page_identifier() {
|
|
185
|
+
const a = this.jsxNode.getAttribute('page');
|
|
186
|
+
if (!a) {
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
if (tsm.Node.isJsxAttribute(a)) {
|
|
190
|
+
const init = a.getInitializer();
|
|
191
|
+
if (tsm.Node.isJsxExpression(init)) {
|
|
192
|
+
const expr = init.getExpression();
|
|
193
|
+
if (tsm.Node.isIdentifier(expr)) {
|
|
194
|
+
return expr;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return undefined;
|
|
174
199
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
return this.getStringAttr('path');
|
|
178
|
-
}
|
|
179
|
-
get prerender() {
|
|
180
|
-
return this.getBoolAttr('prerender');
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// TODO (STREAMING) Remove this once we're sure we don't want to do Render Modes
|
|
184
|
-
get renderMode() {
|
|
185
|
-
return this.getStringAttr('renderMode') || 'stream';
|
|
186
|
-
}
|
|
187
|
-
get path_literal_node() {
|
|
188
|
-
const a = this.jsxNode.getAttribute('path');
|
|
189
|
-
if (!a) {
|
|
190
|
-
return undefined;
|
|
200
|
+
get page_identifier_str() {
|
|
201
|
+
return this.page_identifier?.getText();
|
|
191
202
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (tsm.Node.isStringLiteral(init)) {
|
|
195
|
-
return init;
|
|
196
|
-
}
|
|
203
|
+
get name() {
|
|
204
|
+
return this.getStringAttr('name');
|
|
197
205
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
yield (0, _diagnostics.err)(this.page_identifier, 'Page component not found');
|
|
206
|
+
get path_errorMessage() {
|
|
207
|
+
// TODO: path validation is not strong enough
|
|
208
|
+
if (typeof this.path === 'undefined') {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
validateRoutePath(this.path);
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
catch (e) {
|
|
216
|
+
return e.toString();
|
|
217
|
+
}
|
|
211
218
|
}
|
|
212
|
-
|
|
213
|
-
|
|
219
|
+
get path() {
|
|
220
|
+
return this.getStringAttr('path');
|
|
214
221
|
}
|
|
215
|
-
|
|
216
|
-
|
|
222
|
+
get prerender() {
|
|
223
|
+
return this.getBoolAttr('prerender');
|
|
217
224
|
}
|
|
218
|
-
|
|
219
|
-
|
|
225
|
+
// TODO (STREAMING) Remove this once we're sure we don't want to do Render Modes
|
|
226
|
+
get renderMode() {
|
|
227
|
+
return this.getStringAttr('renderMode') || 'stream';
|
|
220
228
|
}
|
|
221
|
-
|
|
222
|
-
|
|
229
|
+
get path_literal_node() {
|
|
230
|
+
const a = this.jsxNode.getAttribute('path');
|
|
231
|
+
if (!a) {
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
if (tsm.Node.isJsxAttribute(a)) {
|
|
235
|
+
const init = a.getInitializer();
|
|
236
|
+
if (tsm.Node.isStringLiteral(init)) {
|
|
237
|
+
return init;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return undefined;
|
|
223
241
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (!this.path) {
|
|
227
|
-
return false;
|
|
242
|
+
get isNotFound() {
|
|
243
|
+
return typeof this.jsxNode.getAttribute('notfound') !== 'undefined';
|
|
228
244
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (route2 === this) {
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
if (!route2.path) {
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
if (removeParamNames(route2.path) === pathWithNoParamNames) {
|
|
238
|
-
return true;
|
|
239
|
-
}
|
|
245
|
+
get redirect() {
|
|
246
|
+
return this.getStringAttr('redirect');
|
|
240
247
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
248
|
+
*diagnostics() {
|
|
249
|
+
if (this.page_identifier && !this.page) {
|
|
250
|
+
// normally this would be caught by TypeScript
|
|
251
|
+
// but Redwood has some "magic" import behavior going on
|
|
252
|
+
yield err(this.page_identifier, 'Page component not found');
|
|
253
|
+
}
|
|
254
|
+
if (this.path_errorMessage && this.path_literal_node) {
|
|
255
|
+
yield err(this.path_literal_node, this.path_errorMessage, RWError.INVALID_ROUTE_PATH_SYNTAX);
|
|
256
|
+
}
|
|
257
|
+
if (this.hasPathCollision) {
|
|
258
|
+
yield err(this.path_literal_node, 'Duplicate Path');
|
|
259
|
+
}
|
|
260
|
+
if (this.isPrivate && this.isNotFound) {
|
|
261
|
+
yield err(this.jsxNode, "The 'Not Found' page cannot be within a <PrivateSet> or a <Private> tag");
|
|
262
|
+
}
|
|
263
|
+
if (this.isNotFound && this.path) {
|
|
264
|
+
yield err(this.path_literal_node, "The 'Not Found' page cannot have a path");
|
|
265
|
+
}
|
|
266
|
+
for (const warning of this.unprotectedAuthMutationUsages) {
|
|
267
|
+
const { uri, range } = this.location;
|
|
268
|
+
const routeLabel = this.name ?? this.path ?? '(unnamed route)';
|
|
269
|
+
const diagnostic = {
|
|
270
|
+
uri,
|
|
271
|
+
diagnostic: {
|
|
272
|
+
range,
|
|
273
|
+
message: `Route '${routeLabel}' is not wrapped in <PrivateSet>, but its ` +
|
|
274
|
+
`page uses the mutation '${warning.fieldName}', which is ` +
|
|
275
|
+
`marked @requireAuth in ${warning.sdlFilePath} (found in ` +
|
|
276
|
+
`${warning.componentFilePath})`,
|
|
277
|
+
severity: DiagnosticSeverity.Warning,
|
|
278
|
+
code: RWError.UNPROTECTED_ROUTE_USES_AUTH_GATED_MUTATION,
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
yield diagnostic;
|
|
282
|
+
}
|
|
246
283
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
284
|
+
/**
|
|
285
|
+
* For an unprotected route (not wrapped in `<Private>`/`<PrivateSet>`),
|
|
286
|
+
* transitively walks the page's imports to find any GraphQL mutations
|
|
287
|
+
* that are marked `@requireAuth` in the api-side SDL.
|
|
288
|
+
*
|
|
289
|
+
* This is a best-effort static analysis (see `pageMutationUsage.ts`), so
|
|
290
|
+
* any internal failure degrades to "no warning" rather than surfacing a
|
|
291
|
+
* crash diagnostic - this check must never break the other diagnostics.
|
|
292
|
+
*/
|
|
293
|
+
get unprotectedAuthMutationUsages() {
|
|
294
|
+
if (this.isPrivate) {
|
|
295
|
+
return [];
|
|
296
|
+
}
|
|
297
|
+
const page = this.page;
|
|
298
|
+
if (!page) {
|
|
299
|
+
return [];
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
const project = this.parent.parent;
|
|
303
|
+
const requireAuthFields = project.requireAuthMutationFields;
|
|
304
|
+
if (requireAuthFields.size === 0) {
|
|
305
|
+
return [];
|
|
306
|
+
}
|
|
307
|
+
const usedMutations = getMutationFieldsUsedTransitively(project, page.filePath);
|
|
308
|
+
const warnings = [];
|
|
309
|
+
for (const [fieldName, componentFilePath] of usedMutations) {
|
|
310
|
+
const sdlFilePath = requireAuthFields.get(fieldName);
|
|
311
|
+
if (!sdlFilePath) {
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
warnings.push({
|
|
315
|
+
fieldName,
|
|
316
|
+
sdlFilePath,
|
|
317
|
+
componentFilePath: path.relative(project.pathHelper.base, componentFilePath),
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
return warnings;
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
return [];
|
|
324
|
+
}
|
|
253
325
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
326
|
+
get hasPathCollision() {
|
|
327
|
+
if (!this.path) {
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
const pathWithNoParamNames = removeParamNames(this.path);
|
|
331
|
+
for (const route2 of this.parent.routes) {
|
|
332
|
+
if (route2 === this) {
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (!route2.path) {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
if (removeParamNames(route2.path) === pathWithNoParamNames) {
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return false;
|
|
343
|
+
function removeParamNames(p) {
|
|
344
|
+
// TODO: implement
|
|
345
|
+
// foo/{bar}/baz --> foo/{}/baz
|
|
346
|
+
return p;
|
|
347
|
+
}
|
|
274
348
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
349
|
+
getBoolAttr(name) {
|
|
350
|
+
const attr = this.jsxNode.getAttribute(name);
|
|
351
|
+
// No attribute
|
|
352
|
+
if (!attr) {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
// Attribute exists
|
|
356
|
+
if (tsm.Node.isJsxAttribute(attr)) {
|
|
357
|
+
const init = attr.getInitializer();
|
|
358
|
+
// Bool attributes with no initializer are true
|
|
359
|
+
// e.g. <Route prerender />
|
|
360
|
+
if (!init) {
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
if (tsm.Node.isJsxExpression(init)) {
|
|
364
|
+
// If it is explicitly set to true
|
|
365
|
+
// e.g. <Route prerender={true} />
|
|
366
|
+
return tsm.Node.isTrueLiteral(init.getExpression());
|
|
367
|
+
}
|
|
368
|
+
else if (tsm.Node.isStringLiteral(init)) {
|
|
369
|
+
// If its using the incorrect string form, we're accepting it as true
|
|
370
|
+
// e.g. <Route prerender="true" />
|
|
371
|
+
const literalValue = init.getLiteralValue();
|
|
372
|
+
return literalValue === 'true';
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return false;
|
|
281
376
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
377
|
+
getStringAttr(name) {
|
|
378
|
+
const a = this.jsxNode.getAttribute(name);
|
|
379
|
+
if (!a) {
|
|
380
|
+
return undefined;
|
|
381
|
+
}
|
|
382
|
+
if (tsm.Node.isJsxAttribute(a)) {
|
|
383
|
+
const init = a.getInitializer();
|
|
384
|
+
if (tsm.Node.isStringLiteral(init)) {
|
|
385
|
+
return init.getLiteralValue();
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return undefined;
|
|
287
389
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
390
|
+
}
|
|
391
|
+
__decorate([
|
|
392
|
+
lazy()
|
|
393
|
+
], RWRoute.prototype, "id", null);
|
|
394
|
+
__decorate([
|
|
395
|
+
lazy()
|
|
396
|
+
], RWRoute.prototype, "location", null);
|
|
397
|
+
__decorate([
|
|
398
|
+
lazy()
|
|
399
|
+
], RWRoute.prototype, "privateAncestors", null);
|
|
400
|
+
__decorate([
|
|
401
|
+
lazy()
|
|
402
|
+
], RWRoute.prototype, "isPrivate", null);
|
|
403
|
+
__decorate([
|
|
404
|
+
lazy()
|
|
405
|
+
], RWRoute.prototype, "unauthenticated", null);
|
|
406
|
+
__decorate([
|
|
407
|
+
lazy()
|
|
408
|
+
], RWRoute.prototype, "roles", null);
|
|
409
|
+
__decorate([
|
|
410
|
+
lazy()
|
|
411
|
+
], RWRoute.prototype, "hasParameters", null);
|
|
412
|
+
__decorate([
|
|
413
|
+
lazy()
|
|
414
|
+
], RWRoute.prototype, "hasPrerender", null);
|
|
415
|
+
__decorate([
|
|
416
|
+
lazy()
|
|
417
|
+
], RWRoute.prototype, "page", null);
|
|
418
|
+
__decorate([
|
|
419
|
+
lazy()
|
|
420
|
+
], RWRoute.prototype, "page_identifier", null);
|
|
421
|
+
__decorate([
|
|
422
|
+
lazy()
|
|
423
|
+
], RWRoute.prototype, "page_identifier_str", null);
|
|
424
|
+
__decorate([
|
|
425
|
+
lazy()
|
|
426
|
+
], RWRoute.prototype, "name", null);
|
|
427
|
+
__decorate([
|
|
428
|
+
lazy()
|
|
429
|
+
], RWRoute.prototype, "path_errorMessage", null);
|
|
430
|
+
__decorate([
|
|
431
|
+
lazy()
|
|
432
|
+
], RWRoute.prototype, "path", null);
|
|
433
|
+
__decorate([
|
|
434
|
+
lazy()
|
|
435
|
+
], RWRoute.prototype, "prerender", null);
|
|
436
|
+
__decorate([
|
|
437
|
+
lazy()
|
|
438
|
+
], RWRoute.prototype, "renderMode", null);
|
|
439
|
+
__decorate([
|
|
440
|
+
lazy()
|
|
441
|
+
], RWRoute.prototype, "path_literal_node", null);
|
|
442
|
+
__decorate([
|
|
443
|
+
lazy()
|
|
444
|
+
], RWRoute.prototype, "isNotFound", null);
|
|
445
|
+
__decorate([
|
|
446
|
+
lazy()
|
|
447
|
+
], RWRoute.prototype, "redirect", null);
|
|
448
|
+
__decorate([
|
|
449
|
+
lazy()
|
|
450
|
+
], RWRoute.prototype, "unprotectedAuthMutationUsages", null);
|
|
451
|
+
__decorate([
|
|
452
|
+
lazy()
|
|
453
|
+
], RWRoute.prototype, "hasPathCollision", null);
|
|
454
|
+
//# sourceMappingURL=RWRoute.js.map
|