atom.io 0.21.1 → 0.22.0
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/data/dist/index.cjs +136 -63
- package/data/dist/index.d.ts +6 -0
- package/data/dist/index.js +3 -3
- package/data/src/join.ts +135 -51
- package/data/src/struct-family.ts +2 -2
- package/dist/{chunk-RT43TVKP.js → chunk-GVHKIJ3G.js} +1 -1
- package/dist/{chunk-HITX3MO4.js → chunk-JA4V7TJY.js} +135 -62
- package/dist/index.cjs +2 -7
- package/dist/index.d.ts +29 -14
- package/dist/index.js +4 -8
- package/ephemeral/dist/index.cjs +11 -0
- package/ephemeral/dist/index.js +9 -0
- package/ephemeral/package.json +16 -0
- package/ephemeral/src/index.ts +1 -0
- package/eslint-plugin/dist/index.cjs +156 -1
- package/eslint-plugin/dist/index.js +156 -1
- package/eslint-plugin/src/rules/index.ts +1 -0
- package/eslint-plugin/src/rules/lifespan.ts +204 -0
- package/eslint-plugin/src/rules/synchronous-selector-dependencies.ts +1 -65
- package/eslint-plugin/src/walk.ts +73 -0
- package/immortal/dist/index.cjs +100 -0
- package/immortal/dist/index.js +97 -0
- package/immortal/package.json +16 -0
- package/immortal/src/index.ts +2 -0
- package/immortal/src/molecule.ts +134 -0
- package/immortal/src/seek-state.ts +60 -0
- package/internal/dist/index.cjs +186 -146
- package/internal/dist/index.d.ts +29 -13
- package/internal/dist/index.js +185 -146
- package/internal/src/atom/dispose-atom.ts +4 -1
- package/internal/src/families/create-readonly-selector-family.ts +9 -9
- package/internal/src/families/create-regular-atom-family.ts +15 -20
- package/internal/src/families/create-writable-selector-family.ts +6 -7
- package/internal/src/families/find-in-store.ts +11 -5
- package/internal/src/families/index.ts +2 -0
- package/internal/src/families/init-family-member.ts +91 -0
- package/internal/src/families/seek-in-store.ts +106 -0
- package/internal/src/get-state/get-from-store.ts +2 -2
- package/internal/src/mutable/create-mutable-atom-family.ts +17 -23
- package/internal/src/mutable/create-mutable-atom.ts +3 -1
- package/internal/src/mutable/get-json-family.ts +2 -2
- package/internal/src/mutable/get-json-token.ts +27 -12
- package/internal/src/mutable/tracker-family.ts +14 -12
- package/internal/src/not-found-error.ts +11 -3
- package/internal/src/selector/create-readonly-selector.ts +2 -2
- package/internal/src/selector/create-writable-selector.ts +2 -2
- package/internal/src/selector/dispose-selector.ts +40 -23
- package/internal/src/selector/register-selector.ts +8 -5
- package/internal/src/set-state/set-into-store.ts +2 -2
- package/internal/src/store/index.ts +0 -1
- package/internal/src/store/store.ts +18 -5
- package/internal/src/subscribe/subscribe-to-state.ts +2 -2
- package/internal/src/transaction/build-transaction.ts +7 -2
- package/introspection/dist/index.cjs +38 -52
- package/introspection/dist/index.js +38 -52
- package/introspection/src/attach-atom-index.ts +38 -48
- package/introspection/src/attach-selector-index.ts +45 -50
- package/json/dist/index.cjs +38 -4
- package/json/dist/index.js +40 -6
- package/json/src/select-json-family.ts +46 -7
- package/package.json +30 -10
- package/react/dist/index.cjs +1 -1
- package/react/dist/index.js +1 -1
- package/react/src/use-json.ts +1 -1
- package/react-devtools/dist/index.cjs +11 -10
- package/react-devtools/dist/index.js +2 -1
- package/react-devtools/src/StateIndex.tsx +2 -1
- package/react-devtools/src/TimelineIndex.tsx +2 -1
- package/react-devtools/src/TransactionIndex.tsx +7 -7
- package/realtime-client/dist/index.cjs +3 -3
- package/realtime-client/dist/index.js +3 -3
- package/realtime-client/src/pull-mutable-atom-family-member.ts +1 -1
- package/realtime-client/src/pull-mutable-atom.ts +1 -1
- package/realtime-client/src/sync-continuity.ts +1 -2
- package/realtime-react/dist/index.cjs +1 -1
- package/realtime-react/dist/index.js +1 -1
- package/realtime-server/dist/index.cjs +18 -17
- package/realtime-server/dist/index.js +7 -6
- package/realtime-server/src/realtime-continuity-synchronizer.ts +5 -3
- package/realtime-server/src/realtime-mutable-family-provider.ts +2 -1
- package/realtime-server/src/realtime-mutable-provider.ts +1 -1
- package/realtime-testing/dist/index.cjs +6 -2
- package/realtime-testing/dist/index.js +8 -5
- package/realtime-testing/src/setup-realtime-test.tsx +5 -2
- package/src/atom.ts +10 -4
- package/src/index.ts +1 -2
- package/src/selector.ts +10 -4
- package/src/silo.ts +3 -3
- package/src/transaction.ts +5 -2
- package/internal/src/store/withdraw-new-family-member.ts +0 -69
- /package/{src → ephemeral/src}/find-state.ts +0 -0
- /package/src/{dispose.ts → dispose-state.ts} +0 -0
|
@@ -14,6 +14,7 @@ var __export = (target, all) => {
|
|
|
14
14
|
var rules_exports = {};
|
|
15
15
|
__export(rules_exports, {
|
|
16
16
|
explicitStateTypes: () => explicitStateTypes,
|
|
17
|
+
lifespan: () => lifespan,
|
|
17
18
|
synchronousSelectorDependencies: () => synchronousSelectorDependencies
|
|
18
19
|
});
|
|
19
20
|
var createRule = utils.ESLintUtils.RuleCreator(
|
|
@@ -66,7 +67,7 @@ var explicitStateTypes = createRule({
|
|
|
66
67
|
}
|
|
67
68
|
});
|
|
68
69
|
|
|
69
|
-
// eslint-plugin/src/
|
|
70
|
+
// eslint-plugin/src/walk.ts
|
|
70
71
|
function walk(node, callback, depth = 0) {
|
|
71
72
|
callback(node, depth);
|
|
72
73
|
switch (node.type) {
|
|
@@ -125,8 +126,162 @@ function walk(node, callback, depth = 0) {
|
|
|
125
126
|
walk(node.object, callback, depth);
|
|
126
127
|
walk(node.property, callback, depth);
|
|
127
128
|
break;
|
|
129
|
+
case `CallExpression`:
|
|
130
|
+
walk(node.callee, callback, depth);
|
|
131
|
+
for (const argument of node.arguments) {
|
|
132
|
+
walk(argument, callback, depth);
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
128
135
|
}
|
|
129
136
|
}
|
|
137
|
+
|
|
138
|
+
// eslint-plugin/src/rules/lifespan.ts
|
|
139
|
+
var lifespan = {
|
|
140
|
+
meta: {
|
|
141
|
+
type: `problem`,
|
|
142
|
+
docs: {
|
|
143
|
+
description: `atom.io provides tools for short-lived (ephemeral) and long-lived (immortal) stores. This rule allows you to guard against unsafe usage of tools for the other type of store.`,
|
|
144
|
+
category: `Possible Errors`,
|
|
145
|
+
recommended: false,
|
|
146
|
+
url: ``
|
|
147
|
+
// URL to documentation page for this rule
|
|
148
|
+
},
|
|
149
|
+
schema: [
|
|
150
|
+
{
|
|
151
|
+
type: `string`,
|
|
152
|
+
enum: [`ephemeral`, `immortal`],
|
|
153
|
+
default: `ephemeral`
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
},
|
|
157
|
+
create(context) {
|
|
158
|
+
var _a;
|
|
159
|
+
const storeLifespan = (_a = context.options[0]) != null ? _a : `ephemeral`;
|
|
160
|
+
return {
|
|
161
|
+
ImportDeclaration(node) {
|
|
162
|
+
const importSource = node.source.value;
|
|
163
|
+
if (!importSource.startsWith(`atom.io/`)) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const [_, subPackageName] = importSource.split(`/`);
|
|
167
|
+
if (storeLifespan === `immortal` && subPackageName === `ephemeral`) {
|
|
168
|
+
context.report({
|
|
169
|
+
node,
|
|
170
|
+
message: `do not import from "${importSource}" in an ${storeLifespan} store`
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
CallExpression(node) {
|
|
175
|
+
if (storeLifespan === `ephemeral`) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const functionCallee = node.callee.type === `Identifier` ? node.callee : void 0;
|
|
179
|
+
const methodCallee = node.callee.type === `MemberExpression` && node.callee.property.type === `Identifier` ? node.callee.property : void 0;
|
|
180
|
+
const callee = functionCallee != null ? functionCallee : methodCallee;
|
|
181
|
+
if (callee === void 0) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (callee.name === `findState`) {
|
|
185
|
+
context.report({
|
|
186
|
+
node,
|
|
187
|
+
message: `do not use findState in an ${storeLifespan} store`
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
const storeProcedures = [];
|
|
191
|
+
if (callee.name === `selector` || callee.name === `selectorFamily` || callee.name === `transaction`) {
|
|
192
|
+
if (node.arguments[0].type === `ObjectExpression`) {
|
|
193
|
+
const argProperties = node.arguments[0].properties;
|
|
194
|
+
switch (callee.name) {
|
|
195
|
+
case `selector`:
|
|
196
|
+
case `selectorFamily`:
|
|
197
|
+
{
|
|
198
|
+
const getAndSetProps = argProperties.filter(
|
|
199
|
+
(prop) => {
|
|
200
|
+
return `key` in prop && `name` in prop.key && (prop.key.name === `get` || prop.key.name === `set`);
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
switch (callee.name) {
|
|
204
|
+
case `selector`:
|
|
205
|
+
{
|
|
206
|
+
for (const prop of getAndSetProps) {
|
|
207
|
+
if (prop.value.type === `FunctionExpression` || prop.value.type === `ArrowFunctionExpression`) {
|
|
208
|
+
console.log(prop.value);
|
|
209
|
+
storeProcedures.push(prop.value);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
case `selectorFamily`:
|
|
215
|
+
{
|
|
216
|
+
for (const prop of getAndSetProps) {
|
|
217
|
+
const { value } = prop;
|
|
218
|
+
if (value.type === `FunctionExpression` || value.type === `ArrowFunctionExpression`) {
|
|
219
|
+
if (value.body.type === `BlockStatement`) {
|
|
220
|
+
for (const statement of value.body.body) {
|
|
221
|
+
if (statement.type === `ReturnStatement` && statement.argument && (statement.argument.type === `FunctionExpression` || statement.argument.type === `ArrowFunctionExpression`)) {
|
|
222
|
+
storeProcedures.push(statement.argument);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} else if (value.body.type === `FunctionExpression` || value.body.type === `ArrowFunctionExpression`) {
|
|
226
|
+
storeProcedures.push(value.body);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
break;
|
|
235
|
+
case `transaction`:
|
|
236
|
+
{
|
|
237
|
+
const doProp = argProperties.find(
|
|
238
|
+
(prop) => {
|
|
239
|
+
return `key` in prop && `name` in prop.key && prop.key.name === `do`;
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
if (doProp) {
|
|
243
|
+
if (doProp.value.type === `FunctionExpression` || doProp.value.type === `ArrowFunctionExpression`) {
|
|
244
|
+
storeProcedures.push(doProp.value);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
for (const storeProcedure of storeProcedures) {
|
|
253
|
+
const transactorsParam = storeProcedure.params[0];
|
|
254
|
+
const nonDestructuredTransactorsName = transactorsParam && `name` in transactorsParam ? transactorsParam.name : void 0;
|
|
255
|
+
walk(storeProcedure.body, (n) => {
|
|
256
|
+
if (n.type === `CallExpression`) {
|
|
257
|
+
let willReport = false;
|
|
258
|
+
switch (n.callee.type) {
|
|
259
|
+
case `MemberExpression`:
|
|
260
|
+
if (n.callee.object.type === `Identifier` && n.callee.object.name === nonDestructuredTransactorsName && n.callee.property.type === `Identifier` && n.callee.property.name === `find`) {
|
|
261
|
+
willReport = true;
|
|
262
|
+
}
|
|
263
|
+
break;
|
|
264
|
+
case `Identifier`:
|
|
265
|
+
if (n.callee.name === `find`) {
|
|
266
|
+
willReport = true;
|
|
267
|
+
}
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
if (willReport) {
|
|
271
|
+
context.report({
|
|
272
|
+
node: n,
|
|
273
|
+
message: `Using find in a transactor is not allowed in an immortal store.`
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
// eslint-plugin/src/rules/synchronous-selector-dependencies.ts
|
|
130
285
|
var synchronousSelectorDependencies = {
|
|
131
286
|
meta: {
|
|
132
287
|
type: `problem`,
|
|
@@ -5,6 +5,7 @@ import { ESLintUtils } from '@typescript-eslint/utils';
|
|
|
5
5
|
var rules_exports = {};
|
|
6
6
|
__export(rules_exports, {
|
|
7
7
|
explicitStateTypes: () => explicitStateTypes,
|
|
8
|
+
lifespan: () => lifespan,
|
|
8
9
|
synchronousSelectorDependencies: () => synchronousSelectorDependencies
|
|
9
10
|
});
|
|
10
11
|
var createRule = ESLintUtils.RuleCreator(
|
|
@@ -57,7 +58,7 @@ var explicitStateTypes = createRule({
|
|
|
57
58
|
}
|
|
58
59
|
});
|
|
59
60
|
|
|
60
|
-
// eslint-plugin/src/
|
|
61
|
+
// eslint-plugin/src/walk.ts
|
|
61
62
|
function walk(node, callback, depth = 0) {
|
|
62
63
|
callback(node, depth);
|
|
63
64
|
switch (node.type) {
|
|
@@ -116,8 +117,162 @@ function walk(node, callback, depth = 0) {
|
|
|
116
117
|
walk(node.object, callback, depth);
|
|
117
118
|
walk(node.property, callback, depth);
|
|
118
119
|
break;
|
|
120
|
+
case `CallExpression`:
|
|
121
|
+
walk(node.callee, callback, depth);
|
|
122
|
+
for (const argument of node.arguments) {
|
|
123
|
+
walk(argument, callback, depth);
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
119
126
|
}
|
|
120
127
|
}
|
|
128
|
+
|
|
129
|
+
// eslint-plugin/src/rules/lifespan.ts
|
|
130
|
+
var lifespan = {
|
|
131
|
+
meta: {
|
|
132
|
+
type: `problem`,
|
|
133
|
+
docs: {
|
|
134
|
+
description: `atom.io provides tools for short-lived (ephemeral) and long-lived (immortal) stores. This rule allows you to guard against unsafe usage of tools for the other type of store.`,
|
|
135
|
+
category: `Possible Errors`,
|
|
136
|
+
recommended: false,
|
|
137
|
+
url: ``
|
|
138
|
+
// URL to documentation page for this rule
|
|
139
|
+
},
|
|
140
|
+
schema: [
|
|
141
|
+
{
|
|
142
|
+
type: `string`,
|
|
143
|
+
enum: [`ephemeral`, `immortal`],
|
|
144
|
+
default: `ephemeral`
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
create(context) {
|
|
149
|
+
var _a;
|
|
150
|
+
const storeLifespan = (_a = context.options[0]) != null ? _a : `ephemeral`;
|
|
151
|
+
return {
|
|
152
|
+
ImportDeclaration(node) {
|
|
153
|
+
const importSource = node.source.value;
|
|
154
|
+
if (!importSource.startsWith(`atom.io/`)) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const [_, subPackageName] = importSource.split(`/`);
|
|
158
|
+
if (storeLifespan === `immortal` && subPackageName === `ephemeral`) {
|
|
159
|
+
context.report({
|
|
160
|
+
node,
|
|
161
|
+
message: `do not import from "${importSource}" in an ${storeLifespan} store`
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
CallExpression(node) {
|
|
166
|
+
if (storeLifespan === `ephemeral`) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const functionCallee = node.callee.type === `Identifier` ? node.callee : void 0;
|
|
170
|
+
const methodCallee = node.callee.type === `MemberExpression` && node.callee.property.type === `Identifier` ? node.callee.property : void 0;
|
|
171
|
+
const callee = functionCallee != null ? functionCallee : methodCallee;
|
|
172
|
+
if (callee === void 0) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (callee.name === `findState`) {
|
|
176
|
+
context.report({
|
|
177
|
+
node,
|
|
178
|
+
message: `do not use findState in an ${storeLifespan} store`
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
const storeProcedures = [];
|
|
182
|
+
if (callee.name === `selector` || callee.name === `selectorFamily` || callee.name === `transaction`) {
|
|
183
|
+
if (node.arguments[0].type === `ObjectExpression`) {
|
|
184
|
+
const argProperties = node.arguments[0].properties;
|
|
185
|
+
switch (callee.name) {
|
|
186
|
+
case `selector`:
|
|
187
|
+
case `selectorFamily`:
|
|
188
|
+
{
|
|
189
|
+
const getAndSetProps = argProperties.filter(
|
|
190
|
+
(prop) => {
|
|
191
|
+
return `key` in prop && `name` in prop.key && (prop.key.name === `get` || prop.key.name === `set`);
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
switch (callee.name) {
|
|
195
|
+
case `selector`:
|
|
196
|
+
{
|
|
197
|
+
for (const prop of getAndSetProps) {
|
|
198
|
+
if (prop.value.type === `FunctionExpression` || prop.value.type === `ArrowFunctionExpression`) {
|
|
199
|
+
console.log(prop.value);
|
|
200
|
+
storeProcedures.push(prop.value);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
break;
|
|
205
|
+
case `selectorFamily`:
|
|
206
|
+
{
|
|
207
|
+
for (const prop of getAndSetProps) {
|
|
208
|
+
const { value } = prop;
|
|
209
|
+
if (value.type === `FunctionExpression` || value.type === `ArrowFunctionExpression`) {
|
|
210
|
+
if (value.body.type === `BlockStatement`) {
|
|
211
|
+
for (const statement of value.body.body) {
|
|
212
|
+
if (statement.type === `ReturnStatement` && statement.argument && (statement.argument.type === `FunctionExpression` || statement.argument.type === `ArrowFunctionExpression`)) {
|
|
213
|
+
storeProcedures.push(statement.argument);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
} else if (value.body.type === `FunctionExpression` || value.body.type === `ArrowFunctionExpression`) {
|
|
217
|
+
storeProcedures.push(value.body);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
break;
|
|
226
|
+
case `transaction`:
|
|
227
|
+
{
|
|
228
|
+
const doProp = argProperties.find(
|
|
229
|
+
(prop) => {
|
|
230
|
+
return `key` in prop && `name` in prop.key && prop.key.name === `do`;
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
if (doProp) {
|
|
234
|
+
if (doProp.value.type === `FunctionExpression` || doProp.value.type === `ArrowFunctionExpression`) {
|
|
235
|
+
storeProcedures.push(doProp.value);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
for (const storeProcedure of storeProcedures) {
|
|
244
|
+
const transactorsParam = storeProcedure.params[0];
|
|
245
|
+
const nonDestructuredTransactorsName = transactorsParam && `name` in transactorsParam ? transactorsParam.name : void 0;
|
|
246
|
+
walk(storeProcedure.body, (n) => {
|
|
247
|
+
if (n.type === `CallExpression`) {
|
|
248
|
+
let willReport = false;
|
|
249
|
+
switch (n.callee.type) {
|
|
250
|
+
case `MemberExpression`:
|
|
251
|
+
if (n.callee.object.type === `Identifier` && n.callee.object.name === nonDestructuredTransactorsName && n.callee.property.type === `Identifier` && n.callee.property.name === `find`) {
|
|
252
|
+
willReport = true;
|
|
253
|
+
}
|
|
254
|
+
break;
|
|
255
|
+
case `Identifier`:
|
|
256
|
+
if (n.callee.name === `find`) {
|
|
257
|
+
willReport = true;
|
|
258
|
+
}
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
if (willReport) {
|
|
262
|
+
context.report({
|
|
263
|
+
node: n,
|
|
264
|
+
message: `Using find in a transactor is not allowed in an immortal store.`
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// eslint-plugin/src/rules/synchronous-selector-dependencies.ts
|
|
121
276
|
var synchronousSelectorDependencies = {
|
|
122
277
|
meta: {
|
|
123
278
|
type: `problem`,
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import type { Rule } from "eslint"
|
|
2
|
+
import type * as ESTree from "estree"
|
|
3
|
+
|
|
4
|
+
import { walk } from "../walk"
|
|
5
|
+
|
|
6
|
+
export const lifespan = {
|
|
7
|
+
meta: {
|
|
8
|
+
type: `problem`,
|
|
9
|
+
docs: {
|
|
10
|
+
description: `atom.io provides tools for short-lived (ephemeral) and long-lived (immortal) stores. This rule allows you to guard against unsafe usage of tools for the other type of store.`,
|
|
11
|
+
category: `Possible Errors`,
|
|
12
|
+
recommended: false,
|
|
13
|
+
url: ``, // URL to documentation page for this rule
|
|
14
|
+
},
|
|
15
|
+
schema: [
|
|
16
|
+
{
|
|
17
|
+
type: `string`,
|
|
18
|
+
enum: [`ephemeral`, `immortal`],
|
|
19
|
+
default: `ephemeral`,
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
create(context) {
|
|
24
|
+
const storeLifespan = (context.options[0] ?? `ephemeral`) as
|
|
25
|
+
| `ephemeral`
|
|
26
|
+
| `immortal`
|
|
27
|
+
return {
|
|
28
|
+
ImportDeclaration(node) {
|
|
29
|
+
const importSource = node.source.value as string
|
|
30
|
+
if (!importSource.startsWith(`atom.io/`)) {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
const [_, subPackageName] = importSource.split(`/`)
|
|
34
|
+
if (storeLifespan === `immortal` && subPackageName === `ephemeral`) {
|
|
35
|
+
context.report({
|
|
36
|
+
node,
|
|
37
|
+
message: `do not import from "${importSource}" in an ${storeLifespan} store`,
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
CallExpression(node) {
|
|
43
|
+
if (storeLifespan === `ephemeral`) {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const functionCallee =
|
|
48
|
+
node.callee.type === `Identifier` ? node.callee : undefined
|
|
49
|
+
const methodCallee =
|
|
50
|
+
node.callee.type === `MemberExpression` &&
|
|
51
|
+
node.callee.property.type === `Identifier`
|
|
52
|
+
? node.callee.property
|
|
53
|
+
: undefined
|
|
54
|
+
const callee = functionCallee ?? methodCallee
|
|
55
|
+
|
|
56
|
+
if (callee === undefined) {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (callee.name === `findState`) {
|
|
61
|
+
context.report({
|
|
62
|
+
node,
|
|
63
|
+
message: `do not use findState in an ${storeLifespan} store`,
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const storeProcedures: (
|
|
68
|
+
| ESTree.ArrowFunctionExpression
|
|
69
|
+
| ESTree.FunctionExpression
|
|
70
|
+
)[] = []
|
|
71
|
+
if (
|
|
72
|
+
callee.name === `selector` ||
|
|
73
|
+
callee.name === `selectorFamily` ||
|
|
74
|
+
callee.name === `transaction`
|
|
75
|
+
) {
|
|
76
|
+
if (node.arguments[0].type === `ObjectExpression`) {
|
|
77
|
+
const argProperties = node.arguments[0].properties
|
|
78
|
+
switch (callee.name) {
|
|
79
|
+
case `selector`:
|
|
80
|
+
case `selectorFamily`:
|
|
81
|
+
{
|
|
82
|
+
const getAndSetProps = argProperties.filter(
|
|
83
|
+
(prop): prop is ESTree.Property => {
|
|
84
|
+
return (
|
|
85
|
+
`key` in prop &&
|
|
86
|
+
`name` in prop.key &&
|
|
87
|
+
(prop.key.name === `get` || prop.key.name === `set`)
|
|
88
|
+
)
|
|
89
|
+
},
|
|
90
|
+
)
|
|
91
|
+
switch (callee.name) {
|
|
92
|
+
case `selector`:
|
|
93
|
+
{
|
|
94
|
+
for (const prop of getAndSetProps) {
|
|
95
|
+
if (
|
|
96
|
+
prop.value.type === `FunctionExpression` ||
|
|
97
|
+
prop.value.type === `ArrowFunctionExpression`
|
|
98
|
+
) {
|
|
99
|
+
console.log(prop.value)
|
|
100
|
+
storeProcedures.push(prop.value)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
break
|
|
105
|
+
case `selectorFamily`:
|
|
106
|
+
{
|
|
107
|
+
for (const prop of getAndSetProps) {
|
|
108
|
+
const { value } = prop
|
|
109
|
+
if (
|
|
110
|
+
value.type === `FunctionExpression` ||
|
|
111
|
+
value.type === `ArrowFunctionExpression`
|
|
112
|
+
) {
|
|
113
|
+
if (value.body.type === `BlockStatement`) {
|
|
114
|
+
for (const statement of value.body.body) {
|
|
115
|
+
if (
|
|
116
|
+
statement.type === `ReturnStatement` &&
|
|
117
|
+
statement.argument &&
|
|
118
|
+
(statement.argument.type ===
|
|
119
|
+
`FunctionExpression` ||
|
|
120
|
+
statement.argument.type ===
|
|
121
|
+
`ArrowFunctionExpression`)
|
|
122
|
+
) {
|
|
123
|
+
storeProcedures.push(statement.argument)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} else if (
|
|
127
|
+
value.body.type === `FunctionExpression` ||
|
|
128
|
+
value.body.type === `ArrowFunctionExpression`
|
|
129
|
+
) {
|
|
130
|
+
storeProcedures.push(value.body)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
break
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
break
|
|
139
|
+
|
|
140
|
+
case `transaction`:
|
|
141
|
+
{
|
|
142
|
+
const doProp = argProperties.find(
|
|
143
|
+
(prop): prop is ESTree.Property => {
|
|
144
|
+
return (
|
|
145
|
+
`key` in prop &&
|
|
146
|
+
`name` in prop.key &&
|
|
147
|
+
prop.key.name === `do`
|
|
148
|
+
)
|
|
149
|
+
},
|
|
150
|
+
)
|
|
151
|
+
if (doProp) {
|
|
152
|
+
if (
|
|
153
|
+
doProp.value.type === `FunctionExpression` ||
|
|
154
|
+
doProp.value.type === `ArrowFunctionExpression`
|
|
155
|
+
) {
|
|
156
|
+
storeProcedures.push(doProp.value)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
break
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
for (const storeProcedure of storeProcedures) {
|
|
166
|
+
const transactorsParam = storeProcedure.params[0]
|
|
167
|
+
const nonDestructuredTransactorsName =
|
|
168
|
+
transactorsParam && `name` in transactorsParam
|
|
169
|
+
? transactorsParam.name
|
|
170
|
+
: undefined
|
|
171
|
+
walk(storeProcedure.body, (n) => {
|
|
172
|
+
// console.log(`${`\t`.repeat(depth)}${n.type} ${n.name ?? ``}`)
|
|
173
|
+
if (n.type === `CallExpression`) {
|
|
174
|
+
let willReport = false
|
|
175
|
+
switch (n.callee.type) {
|
|
176
|
+
case `MemberExpression`:
|
|
177
|
+
if (
|
|
178
|
+
n.callee.object.type === `Identifier` &&
|
|
179
|
+
n.callee.object.name === nonDestructuredTransactorsName &&
|
|
180
|
+
n.callee.property.type === `Identifier` &&
|
|
181
|
+
n.callee.property.name === `find`
|
|
182
|
+
) {
|
|
183
|
+
willReport = true
|
|
184
|
+
}
|
|
185
|
+
break
|
|
186
|
+
case `Identifier`:
|
|
187
|
+
if (n.callee.name === `find`) {
|
|
188
|
+
willReport = true
|
|
189
|
+
}
|
|
190
|
+
break
|
|
191
|
+
}
|
|
192
|
+
if (willReport) {
|
|
193
|
+
context.report({
|
|
194
|
+
node: n,
|
|
195
|
+
message: `Using find in a transactor is not allowed in an immortal store.`,
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
} satisfies Rule.RuleModule
|
|
@@ -1,71 +1,7 @@
|
|
|
1
1
|
import type { Rule } from "eslint"
|
|
2
2
|
import type * as ESTree from "estree"
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
node: ESTree.Node,
|
|
6
|
-
callback: (node: ESTree.Node, depth: number) => void,
|
|
7
|
-
depth = 0,
|
|
8
|
-
) {
|
|
9
|
-
callback(node, depth)
|
|
10
|
-
|
|
11
|
-
switch (node.type) {
|
|
12
|
-
case `FunctionDeclaration`:
|
|
13
|
-
case `FunctionExpression`:
|
|
14
|
-
case `ArrowFunctionExpression`:
|
|
15
|
-
for (const param of node.params) {
|
|
16
|
-
walk(param, callback, depth + 1)
|
|
17
|
-
}
|
|
18
|
-
walk(node.body, callback, depth + 1)
|
|
19
|
-
break
|
|
20
|
-
case `BlockStatement`:
|
|
21
|
-
for (const statement of node.body) {
|
|
22
|
-
walk(statement, callback, depth + 1)
|
|
23
|
-
}
|
|
24
|
-
break
|
|
25
|
-
case `IfStatement`:
|
|
26
|
-
walk(node.test, callback, depth)
|
|
27
|
-
walk(node.consequent, callback, depth)
|
|
28
|
-
if (node.alternate) {
|
|
29
|
-
walk(node.alternate, callback, depth)
|
|
30
|
-
}
|
|
31
|
-
break
|
|
32
|
-
case `SwitchStatement`:
|
|
33
|
-
walk(node.discriminant, callback, depth + 1)
|
|
34
|
-
for (const caseOrDefault of node.cases) {
|
|
35
|
-
walk(caseOrDefault, callback, depth)
|
|
36
|
-
}
|
|
37
|
-
break
|
|
38
|
-
case `ReturnStatement`:
|
|
39
|
-
if (node.argument) {
|
|
40
|
-
walk(node.argument, callback, depth)
|
|
41
|
-
}
|
|
42
|
-
break
|
|
43
|
-
case `SwitchCase`:
|
|
44
|
-
if (node.test) {
|
|
45
|
-
walk(node.test, callback, depth)
|
|
46
|
-
}
|
|
47
|
-
for (const statement of node.consequent) {
|
|
48
|
-
walk(statement, callback, depth)
|
|
49
|
-
}
|
|
50
|
-
break
|
|
51
|
-
case `VariableDeclaration`:
|
|
52
|
-
for (const declaration of node.declarations) {
|
|
53
|
-
walk(declaration, callback, depth)
|
|
54
|
-
if (declaration.init) {
|
|
55
|
-
walk(declaration.init, callback, depth)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
break
|
|
59
|
-
case `BinaryExpression`:
|
|
60
|
-
walk(node.left, callback, depth)
|
|
61
|
-
walk(node.right, callback, depth)
|
|
62
|
-
break
|
|
63
|
-
case `MemberExpression`:
|
|
64
|
-
walk(node.object, callback, depth)
|
|
65
|
-
walk(node.property, callback, depth)
|
|
66
|
-
break
|
|
67
|
-
}
|
|
68
|
-
}
|
|
4
|
+
import { walk } from "../walk"
|
|
69
5
|
|
|
70
6
|
export const synchronousSelectorDependencies = {
|
|
71
7
|
meta: {
|