@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.
Files changed (118) hide show
  1. package/README.md +1 -1
  2. package/dist/errors.d.ts +2 -1
  3. package/dist/errors.d.ts.map +1 -1
  4. package/dist/errors.js +10 -15
  5. package/dist/errors.js.map +1 -0
  6. package/dist/index.d.ts +7 -7
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +40 -67
  9. package/dist/index.js.map +1 -0
  10. package/dist/model/RWCell.d.ts +4 -4
  11. package/dist/model/RWCell.d.ts.map +1 -1
  12. package/dist/model/RWCell.js +111 -103
  13. package/dist/model/RWCell.js.map +1 -0
  14. package/dist/model/RWComponent.d.ts +2 -2
  15. package/dist/model/RWComponent.d.ts.map +1 -1
  16. package/dist/model/RWComponent.js +46 -41
  17. package/dist/model/RWComponent.js.map +1 -0
  18. package/dist/model/RWEnvHelper.d.ts +4 -4
  19. package/dist/model/RWEnvHelper.d.ts.map +1 -1
  20. package/dist/model/RWEnvHelper.js +233 -205
  21. package/dist/model/RWEnvHelper.js.map +1 -0
  22. package/dist/model/RWFunction.d.ts +2 -2
  23. package/dist/model/RWFunction.d.ts.map +1 -1
  24. package/dist/model/RWFunction.js +10 -15
  25. package/dist/model/RWFunction.js.map +1 -0
  26. package/dist/model/RWLayout.d.ts +2 -2
  27. package/dist/model/RWLayout.d.ts.map +1 -1
  28. package/dist/model/RWLayout.js +10 -15
  29. package/dist/model/RWLayout.js.map +1 -0
  30. package/dist/model/RWPage.d.ts +3 -3
  31. package/dist/model/RWPage.d.ts.map +1 -1
  32. package/dist/model/RWPage.js +61 -57
  33. package/dist/model/RWPage.js.map +1 -0
  34. package/dist/model/RWProject.d.ts +22 -18
  35. package/dist/model/RWProject.d.ts.map +1 -1
  36. package/dist/model/RWProject.js +257 -164
  37. package/dist/model/RWProject.js.map +1 -0
  38. package/dist/model/RWRoute.d.ts +32 -6
  39. package/dist/model/RWRoute.d.ts.map +1 -1
  40. package/dist/model/RWRoute.js +424 -260
  41. package/dist/model/RWRoute.js.map +1 -0
  42. package/dist/model/RWRouter.d.ts +4 -4
  43. package/dist/model/RWRouter.d.ts.map +1 -1
  44. package/dist/model/RWRouter.js +130 -126
  45. package/dist/model/RWRouter.js.map +1 -0
  46. package/dist/model/RWSDL.d.ts +5 -5
  47. package/dist/model/RWSDL.d.ts.map +1 -1
  48. package/dist/model/RWSDL.js +96 -84
  49. package/dist/model/RWSDL.js.map +1 -0
  50. package/dist/model/RWSDLField.d.ts +6 -6
  51. package/dist/model/RWSDLField.d.ts.map +1 -1
  52. package/dist/model/RWSDLField.js +79 -81
  53. package/dist/model/RWSDLField.js.map +1 -0
  54. package/dist/model/RWService.d.ts +4 -4
  55. package/dist/model/RWService.d.ts.map +1 -1
  56. package/dist/model/RWService.js +76 -76
  57. package/dist/model/RWService.js.map +1 -0
  58. package/dist/model/RWServiceFunction.d.ts +4 -4
  59. package/dist/model/RWServiceFunction.d.ts.map +1 -1
  60. package/dist/model/RWServiceFunction.js +95 -97
  61. package/dist/model/RWServiceFunction.js.map +1 -0
  62. package/dist/model/RWTOML.d.ts +3 -3
  63. package/dist/model/RWTOML.d.ts.map +1 -1
  64. package/dist/model/RWTOML.js +53 -55
  65. package/dist/model/RWTOML.js.map +1 -0
  66. package/dist/model/index.d.ts +2 -2
  67. package/dist/model/index.d.ts.map +1 -1
  68. package/dist/model/index.js +3 -20
  69. package/dist/model/index.js.map +1 -0
  70. package/dist/model/util/pageMutationUsage.d.ts +18 -0
  71. package/dist/model/util/pageMutationUsage.d.ts.map +1 -0
  72. package/dist/model/util/pageMutationUsage.js +256 -0
  73. package/dist/model/util/pageMutationUsage.js.map +1 -0
  74. package/dist/model/util/process_env.js +44 -62
  75. package/dist/model/util/process_env.js.map +1 -0
  76. package/dist/nodes.d.ts +2 -2
  77. package/dist/nodes.d.ts.map +1 -1
  78. package/dist/nodes.js +171 -164
  79. package/dist/nodes.js.map +1 -0
  80. package/dist/util.js +23 -33
  81. package/dist/util.js.map +1 -0
  82. package/dist/x/Array.d.ts.map +1 -1
  83. package/dist/x/Array.js +15 -25
  84. package/dist/x/Array.js.map +1 -0
  85. package/dist/x/Location.d.ts +1 -1
  86. package/dist/x/Location.d.ts.map +1 -1
  87. package/dist/x/Location.js +11 -17
  88. package/dist/x/Location.js.map +1 -0
  89. package/dist/x/Position.js +18 -29
  90. package/dist/x/Position.js.map +1 -0
  91. package/dist/x/Range.d.ts +1 -1
  92. package/dist/x/Range.d.ts.map +1 -1
  93. package/dist/x/Range.js +17 -22
  94. package/dist/x/Range.js.map +1 -0
  95. package/dist/x/URL.js +59 -75
  96. package/dist/x/URL.js.map +1 -0
  97. package/dist/x/child_process.d.ts +1 -1
  98. package/dist/x/child_process.d.ts.map +1 -1
  99. package/dist/x/child_process.js +35 -49
  100. package/dist/x/child_process.js.map +1 -0
  101. package/dist/x/decorators.d.ts +2 -2
  102. package/dist/x/decorators.d.ts.map +1 -1
  103. package/dist/x/decorators.js +46 -26
  104. package/dist/x/decorators.js.map +1 -0
  105. package/dist/x/diagnostics.d.ts +3 -3
  106. package/dist/x/diagnostics.d.ts.map +1 -1
  107. package/dist/x/diagnostics.js +163 -259
  108. package/dist/x/diagnostics.js.map +1 -0
  109. package/dist/x/path.js +36 -55
  110. package/dist/x/path.js.map +1 -0
  111. package/dist/x/prisma.d.ts +2 -2
  112. package/dist/x/prisma.d.ts.map +1 -1
  113. package/dist/x/prisma.js +32 -55
  114. package/dist/x/prisma.js.map +1 -0
  115. package/dist/x/ts-morph.js +34 -45
  116. package/dist/x/ts-morph.js.map +1 -0
  117. package/package.json +46 -22
  118. package/LICENSE +0 -21
@@ -1,290 +1,454 @@
1
- "use strict";
2
-
3
- var _Object$defineProperty = require("@babel/runtime-corejs3/core-js/object/define-property");
4
- var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
5
- var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard").default;
6
- _Object$defineProperty(exports, "__esModule", {
7
- value: true
8
- });
9
- exports.RWRoute = void 0;
10
- require("core-js/modules/es.json.parse.js");
11
- var _startsWith = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/instance/starts-with"));
12
- var _endsWith = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/instance/ends-with"));
13
- var _isArray = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/array/is-array"));
14
- var _filter = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/instance/filter"));
15
- var _map = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/instance/map"));
16
- var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/instance/includes"));
17
- var _find = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/instance/find"));
18
- var _getOwnPropertyDescriptor = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/object/get-own-property-descriptor"));
19
- var _applyDecoratedDescriptor2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/applyDecoratedDescriptor"));
20
- var tsm = _interopRequireWildcard(require("ts-morph"));
21
- var _errors = require("../errors");
22
- var _nodes = require("../nodes");
23
- var _util = require("../util");
24
- var _decorators = require("../x/decorators");
25
- var _diagnostics = require("../x/diagnostics");
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
- const a = this.jsxNode.getParentIfKind(tsm.SyntaxKind.JsxElement)?.getOpeningElement().getAttribute('unauthenticated');
54
- if (!a) {
55
- return undefined;
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
- if (tsm.Node.isJsxAttribute(a)) {
58
- const init = a.getInitializer();
59
- if (tsm.Node.isStringLiteral(init)) {
60
- return init.getLiteralValue();
61
- }
32
+ get location() {
33
+ return LocationLike_toLocation(this.jsxNode);
62
34
  }
63
- return undefined;
64
- }
65
- get roles() {
66
- if (!this.isPrivate) {
67
- return undefined;
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
- const a = this.jsxNode.getParentIfKind(tsm.SyntaxKind.JsxElement)?.getOpeningElement().getAttribute('roles');
70
- if (!a) {
71
- return undefined;
64
+ get isPrivate() {
65
+ return this.privateAncestors.length > 0;
72
66
  }
73
- if (tsm.Node.isJsxAttribute(a)) {
74
- const init = a.getInitializer();
75
-
76
- // Handle string literals
77
- if (tsm.Node.isStringLiteral(init)) {
78
- const literalValue = init.getLiteralValue();
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
- } catch {
91
- // If parsing fails, return undefined
92
- return undefined;
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
- return undefined;
115
- }
116
- get hasParameters() {
117
- var _context3;
118
- if (!this.path) {
119
- return false;
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
- // KLUDGE: we need a good path parsing library here
122
- return (0, _includes.default)(_context3 = this.path).call(_context3, '{');
123
- }
124
- get hasPrerender() {
125
- return this.prerender;
126
- }
127
-
128
- /**
129
- * The associated Redwood Page node, if any
130
- */
131
-
132
- get page() {
133
- var _context4;
134
- if (!this.page_identifier_str) {
135
- return undefined;
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
- return (0, _find.default)(_context4 = this.parent.parent.pages).call(_context4, p => p.constName === this.page_identifier_str);
138
- }
139
- /**
140
- * <Route path="" page={THIS_IDENTIFIER}/>
141
- */
142
- get page_identifier() {
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
- if (tsm.Node.isJsxAttribute(a)) {
148
- const init = a.getInitializer();
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
- return undefined;
157
- }
158
- get page_identifier_str() {
159
- return this.page_identifier?.getText();
160
- }
161
- get name() {
162
- return this.getStringAttr('name');
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
- try {
170
- (0, _util.validateRoutePath)(this.path);
171
- return undefined;
172
- } catch (e) {
173
- return e.toString();
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
- get path() {
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
- if (tsm.Node.isJsxAttribute(a)) {
193
- const init = a.getInitializer();
194
- if (tsm.Node.isStringLiteral(init)) {
195
- return init;
196
- }
203
+ get name() {
204
+ return this.getStringAttr('name');
197
205
  }
198
- return undefined;
199
- }
200
- get isNotFound() {
201
- return typeof this.jsxNode.getAttribute('notfound') !== 'undefined';
202
- }
203
- get redirect() {
204
- return this.getStringAttr('redirect');
205
- }
206
- *diagnostics() {
207
- if (this.page_identifier && !this.page) {
208
- // normally this would be caught by TypeScript
209
- // but Redwood has some "magic" import behavior going on
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
- if (this.path_errorMessage && this.path_literal_node) {
213
- yield (0, _diagnostics.err)(this.path_literal_node, this.path_errorMessage, _errors.RWError.INVALID_ROUTE_PATH_SYNTAX);
219
+ get path() {
220
+ return this.getStringAttr('path');
214
221
  }
215
- if (this.hasPathCollision) {
216
- yield (0, _diagnostics.err)(this.path_literal_node, 'Duplicate Path');
222
+ get prerender() {
223
+ return this.getBoolAttr('prerender');
217
224
  }
218
- if (this.isPrivate && this.isNotFound) {
219
- yield (0, _diagnostics.err)(this.jsxNode, "The 'Not Found' page cannot be within a <PrivateSet> or a <Private> tag");
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
- if (this.isNotFound && this.path) {
222
- yield (0, _diagnostics.err)(this.path_literal_node, "The 'Not Found' page cannot have a path");
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
- get hasPathCollision() {
226
- if (!this.path) {
227
- return false;
242
+ get isNotFound() {
243
+ return typeof this.jsxNode.getAttribute('notfound') !== 'undefined';
228
244
  }
229
- const pathWithNoParamNames = removeParamNames(this.path);
230
- for (const route2 of this.parent.routes) {
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
- return false;
242
- function removeParamNames(p) {
243
- // TODO: implement
244
- // foo/{bar}/baz --> foo/{}/baz
245
- return p;
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
- getBoolAttr(name) {
249
- const attr = this.jsxNode.getAttribute(name);
250
- // No attribute
251
- if (!attr) {
252
- return false;
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
- // Attribute exists
256
- if (tsm.Node.isJsxAttribute(attr)) {
257
- const init = attr.getInitializer();
258
-
259
- // Bool attributes with no initializer are true
260
- // e.g. <Route prerender />
261
- if (!init) {
262
- return true;
263
- }
264
- if (tsm.Node.isJsxExpression(init)) {
265
- // If it is explicitly set to true
266
- // e.g. <Route prerender={true} />
267
- return tsm.Node.isTrueLiteral(init.getExpression());
268
- } else if (tsm.Node.isStringLiteral(init)) {
269
- // If its using the incorrect string form, we're accepting it as true
270
- // e.g. <Route prerender="true" />
271
- const literalValue = init.getLiteralValue();
272
- return literalValue === 'true';
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
- return false;
276
- }
277
- getStringAttr(name) {
278
- const a = this.jsxNode.getAttribute(name);
279
- if (!a) {
280
- return undefined;
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
- if (tsm.Node.isJsxAttribute(a)) {
283
- const init = a.getInitializer();
284
- if (tsm.Node.isStringLiteral(init)) {
285
- return init.getLiteralValue();
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
- return undefined;
289
- }
290
- }, (0, _applyDecoratedDescriptor2.default)(_class.prototype, "id", [_dec], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "id"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "location", [_dec2], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "location"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "isPrivate", [_dec3], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "isPrivate"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "unauthenticated", [_dec4], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "unauthenticated"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "roles", [_dec5], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "roles"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "hasParameters", [_dec6], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "hasParameters"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "hasPrerender", [_dec7], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "hasPrerender"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "page", [_dec8], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "page"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "page_identifier", [_dec9], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "page_identifier"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "page_identifier_str", [_dec0], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "page_identifier_str"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "name", [_dec1], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "name"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "path_errorMessage", [_dec10], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "path_errorMessage"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "path", [_dec11], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "path"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "prerender", [_dec12], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "prerender"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "renderMode", [_dec13], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "renderMode"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "path_literal_node", [_dec14], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "path_literal_node"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "isNotFound", [_dec15], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "isNotFound"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "redirect", [_dec16], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "redirect"), _class.prototype), (0, _applyDecoratedDescriptor2.default)(_class.prototype, "hasPathCollision", [_dec17], (0, _getOwnPropertyDescriptor.default)(_class.prototype, "hasPathCollision"), _class.prototype), _class);
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