@expo/entity-codemod 0.40.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/README.md +26 -0
- package/build/index.d.ts +0 -0
- package/build/index.js +2 -0
- package/build/index.js.map +1 -0
- package/build/transforms/__tests__/v0.39.0-v0.40.0-test.d.ts +1 -0
- package/build/transforms/__tests__/v0.39.0-v0.40.0-test.js +16 -0
- package/build/transforms/__tests__/v0.39.0-v0.40.0-test.js.map +1 -0
- package/build/transforms/v0.39.0-v0.40.0.d.ts +2 -0
- package/build/transforms/v0.39.0-v0.40.0.js +128 -0
- package/build/transforms/v0.39.0-v0.40.0.js.map +1 -0
- package/package.json +40 -0
- package/src/index.ts +0 -0
- package/src/transforms/__testfixtures__/v0.39.0-v0.40.0/test1.input.ts +79 -0
- package/src/transforms/__testfixtures__/v0.39.0-v0.40.0/test1.output.ts +79 -0
- package/src/transforms/__testfixtures__/v0.39.0-v0.40.0/test2.input.ts +10 -0
- package/src/transforms/__testfixtures__/v0.39.0-v0.40.0/test2.output.ts +10 -0
- package/src/transforms/__testfixtures__/v0.39.0-v0.40.0/test3.input.ts +5 -0
- package/src/transforms/__testfixtures__/v0.39.0-v0.40.0/test3.output.ts +5 -0
- package/src/transforms/__tests__/v0.39.0-v0.40.0-test.ts +16 -0
- package/src/transforms/v0.39.0-v0.40.0.ts +213 -0
package/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @expo/entity-codemod
|
|
2
|
+
|
|
3
|
+
A package containing jscodeshift codemods for @expo/entity upgrades.
|
|
4
|
+
|
|
5
|
+
Codemods are transformations that run on your codebase programmatically. This allows for a large amount of changes to be applied without having to manually go through every file.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
These should be used via the [jscodeshift CLI](https://github.com/facebook/jscodeshift?tab=readme-ov-file#usage-cli).
|
|
10
|
+
|
|
11
|
+
For example:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
yarn add -D @expo/entity-codemod
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then, in package.json scripts:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
"jscodeshift": "jscodeshift --extensions=ts --parser=ts"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
And finally:
|
|
24
|
+
```sh
|
|
25
|
+
yarn jscodeshift src -t node_modules/@expo/entity-codemod/build/v0.39.0-v0.40.0.js
|
|
26
|
+
```
|
package/build/index.d.ts
ADDED
|
File without changes
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const fs_1 = require("fs");
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
jest.autoMockOff();
|
|
6
|
+
const defineTest = require('jscodeshift/dist/testUtils').defineTest;
|
|
7
|
+
const fixtureDir = 'v0.39.0-v0.40.0';
|
|
8
|
+
const fixtureDirPath = (0, path_1.join)(__dirname, '..', '__testfixtures__', fixtureDir);
|
|
9
|
+
const fixtures = (0, fs_1.readdirSync)(fixtureDirPath)
|
|
10
|
+
.filter((file) => file.endsWith('.input.ts'))
|
|
11
|
+
.map((file) => file.replace('.input.ts', ''));
|
|
12
|
+
for (const fixture of fixtures) {
|
|
13
|
+
const prefix = `${fixtureDir}/${fixture}`;
|
|
14
|
+
defineTest(__dirname, 'v0.39.0-v0.40.0', null, prefix, { parser: 'ts' });
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=v0.39.0-v0.40.0-test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v0.39.0-v0.40.0-test.js","sourceRoot":"","sources":["../../../src/transforms/__tests__/v0.39.0-v0.40.0-test.ts"],"names":[],"mappings":";;AAAA,2BAAiC;AACjC,+BAA4B;AAE5B,IAAI,CAAC,WAAW,EAAE,CAAC;AACnB,MAAM,UAAU,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC,UAAU,CAAC;AAEpE,MAAM,UAAU,GAAG,iBAAiB,CAAC;AACrC,MAAM,cAAc,GAAG,IAAA,WAAI,EAAC,SAAS,EAAE,IAAI,EAAE,kBAAkB,EAAE,UAAU,CAAC,CAAC;AAC7E,MAAM,QAAQ,GAAG,IAAA,gBAAW,EAAC,cAAc,CAAC;KACzC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;KAC5C,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC;AAEhD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,GAAG,UAAU,IAAI,OAAO,EAAE,CAAC;IAC1C,UAAU,CAAC,SAAS,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = transformer;
|
|
4
|
+
function transformEnforcingEntityChainMethod(j, root, type, crudType, methodBefore, methodAfter) {
|
|
5
|
+
// Find all entity creator expressions of the form
|
|
6
|
+
// `TestEntity.creator(viewerContext).setField('wat', 2).enforceCreateAsync()`
|
|
7
|
+
root
|
|
8
|
+
.find(j.CallExpression, {
|
|
9
|
+
callee: {
|
|
10
|
+
type: 'MemberExpression',
|
|
11
|
+
property: {
|
|
12
|
+
name: methodBefore,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
})
|
|
16
|
+
.forEach((path) => {
|
|
17
|
+
const enforceCreateAsyncCallExpression = path.node; // TestEntity.creator(viewerContext).setField('wat', 2).enforceCreateAsync()
|
|
18
|
+
const enforceCreateAsyncCallee = enforceCreateAsyncCallExpression.callee; // TestEntity.creator(viewerContext).setField('wat', 2).enforceCreateAsync
|
|
19
|
+
if (enforceCreateAsyncCallee.type !== 'MemberExpression') {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (enforceCreateAsyncCallee.property.type !== 'Identifier') {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// traverse in until we find the first non-setField call
|
|
26
|
+
let lastCallee = enforceCreateAsyncCallee;
|
|
27
|
+
while (true) {
|
|
28
|
+
// TestEntity.creator(viewerContext).setField('wat', 2)
|
|
29
|
+
const maybeSetFieldObjectCallExpression = lastCallee.object;
|
|
30
|
+
if (maybeSetFieldObjectCallExpression.type !== 'CallExpression') {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
// TestEntity.creator(viewerContext).setField
|
|
34
|
+
const maybeSetFieldObjectCallee = maybeSetFieldObjectCallExpression.callee;
|
|
35
|
+
if (maybeSetFieldObjectCallee.type !== 'MemberExpression') {
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
const maybeSetFieldObjectCalleeProperty = maybeSetFieldObjectCallee.property;
|
|
39
|
+
if (maybeSetFieldObjectCalleeProperty.type !== 'Identifier') {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
if (maybeSetFieldObjectCalleeProperty.name === 'setField') {
|
|
43
|
+
lastCallee = maybeSetFieldObjectCallee;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// TestEntity.creator(viewerContext)
|
|
50
|
+
const maybeCreatorCallExpression = lastCallee.object;
|
|
51
|
+
if (maybeCreatorCallExpression.type !== 'CallExpression') {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (maybeCreatorCallExpression.callee.type !== 'MemberExpression' ||
|
|
55
|
+
maybeCreatorCallExpression.callee.property.type !== 'Identifier' ||
|
|
56
|
+
maybeCreatorCallExpression.callee.property.name !== crudType) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// TestEntity.creator(viewerContext).enforcing()
|
|
60
|
+
const newCreatorCallExpression = j.callExpression(j.memberExpression(maybeCreatorCallExpression, j.identifier(type)), []);
|
|
61
|
+
// TestEntity.creator(viewerContext).enforcing().setField('wat', 2).createAsync()
|
|
62
|
+
lastCallee.object = newCreatorCallExpression;
|
|
63
|
+
// change enforceCreateAsync to createAsync at the end so if this returns early it doesn't mutate
|
|
64
|
+
enforceCreateAsyncCallee.property.name = methodAfter;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function transformEnforcingEntityDeleteMethod(j, root, type, methodBefore, methodAfter) {
|
|
68
|
+
// Find all entity creator expressions of the form
|
|
69
|
+
// `TestEntity.enforceDeleteAsync(entity)`
|
|
70
|
+
root
|
|
71
|
+
.find(j.CallExpression, {
|
|
72
|
+
callee: {
|
|
73
|
+
type: 'MemberExpression',
|
|
74
|
+
property: {
|
|
75
|
+
name: methodBefore,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
})
|
|
79
|
+
.forEach((path) => {
|
|
80
|
+
const enforceDeleteAsyncCallExpression = path.node; // TestEntity.enforceDeleteAsync(entity)
|
|
81
|
+
const args = enforceDeleteAsyncCallExpression.arguments; // [entity]
|
|
82
|
+
enforceDeleteAsyncCallExpression.arguments = [];
|
|
83
|
+
const enforceDeleteAsyncCallee = enforceDeleteAsyncCallExpression.callee; // TestEntity.enforceDeleteAsync
|
|
84
|
+
if (enforceDeleteAsyncCallee.type !== 'MemberExpression') {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// change enforceDeleteAsync to deleteAsync
|
|
88
|
+
if (enforceDeleteAsyncCallee.property.type !== 'Identifier') {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
enforceDeleteAsyncCallee.property.name = methodAfter;
|
|
92
|
+
enforceDeleteAsyncCallee.object = j.callExpression(j.memberExpression(j.callExpression(j.memberExpression(enforceDeleteAsyncCallee.object, j.identifier('deleter')), args), j.identifier(type)), []);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function transformAssociationLoaderMethod(j, root) {
|
|
96
|
+
// Find all entity associationLoader expressions of the form
|
|
97
|
+
// `this.associationLoader()`
|
|
98
|
+
root
|
|
99
|
+
.find(j.CallExpression, {
|
|
100
|
+
callee: {
|
|
101
|
+
type: 'MemberExpression',
|
|
102
|
+
property: {
|
|
103
|
+
name: 'associationLoader',
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
.forEach((path) => {
|
|
108
|
+
const associationLoaderCallExpression = path.node; // this.associationLoader()
|
|
109
|
+
// replace with this.associationLoader().withAuthorizationResults()
|
|
110
|
+
path.replace(j.callExpression(j.memberExpression(associationLoaderCallExpression, j.identifier('withAuthorizationResults')), []));
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function transformer(file, api, _options) {
|
|
114
|
+
const j = api.jscodeshift;
|
|
115
|
+
const root = j.withParser('ts')(file.source);
|
|
116
|
+
// do authorization results first since it uses the same detection pattern as enforcing post-transform (i.e. it looks for createAsync)
|
|
117
|
+
transformEnforcingEntityChainMethod(j, root, 'withAuthorizationResults', 'creator', 'createAsync', 'createAsync');
|
|
118
|
+
transformEnforcingEntityChainMethod(j, root, 'withAuthorizationResults', 'updater', 'updateAsync', 'updateAsync');
|
|
119
|
+
transformEnforcingEntityDeleteMethod(j, root, 'withAuthorizationResults', 'deleteAsync', 'deleteAsync');
|
|
120
|
+
// now do enforcing
|
|
121
|
+
transformEnforcingEntityChainMethod(j, root, 'enforcing', 'creator', 'enforceCreateAsync', 'createAsync');
|
|
122
|
+
transformEnforcingEntityChainMethod(j, root, 'enforcing', 'updater', 'enforceUpdateAsync', 'updateAsync');
|
|
123
|
+
transformEnforcingEntityDeleteMethod(j, root, 'enforcing', 'enforceDeleteAsync', 'deleteAsync');
|
|
124
|
+
// association loader
|
|
125
|
+
transformAssociationLoaderMethod(j, root);
|
|
126
|
+
return root.toSource();
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=v0.39.0-v0.40.0.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v0.39.0-v0.40.0.js","sourceRoot":"","sources":["../../src/transforms/v0.39.0-v0.40.0.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@expo/entity-codemod",
|
|
3
|
+
"version": "0.40.0",
|
|
4
|
+
"description": "jscodeshift codemods for @expo/entity upgrades",
|
|
5
|
+
"files": [
|
|
6
|
+
"build",
|
|
7
|
+
"src"
|
|
8
|
+
],
|
|
9
|
+
"main": "build/index.js",
|
|
10
|
+
"types": "build/index.d.ts",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"tsc": "tsc",
|
|
13
|
+
"clean": "rm -rf build coverage coverage-integration",
|
|
14
|
+
"lint": "eslint src",
|
|
15
|
+
"lint-fix": "eslint src --fix",
|
|
16
|
+
"test": "jest --rootDir . --config ../../resources/jest.config.js"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=16"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"entity"
|
|
23
|
+
],
|
|
24
|
+
"author": "Expo",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/jest": "^29.5.12",
|
|
28
|
+
"@types/jscodeshift": "^0.12.0",
|
|
29
|
+
"@types/node": "^20.14.1",
|
|
30
|
+
"eslint": "^8.57.1",
|
|
31
|
+
"eslint-config-universe": "^14.0.0",
|
|
32
|
+
"eslint-plugin-tsdoc": "^0.3.0",
|
|
33
|
+
"jest": "^29.7.0",
|
|
34
|
+
"jscodeshift": "^17.1.2",
|
|
35
|
+
"prettier": "^3.3.3",
|
|
36
|
+
"ts-jest": "^29.2.5",
|
|
37
|
+
"ts-mockito": "^2.6.1",
|
|
38
|
+
"typescript": "^5.7.3"
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/index.ts
ADDED
|
File without changes
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
|
|
3
|
+
import { ViewerContext } from '@expo/entity';
|
|
4
|
+
|
|
5
|
+
async function testWithAuthorizationResults(viewerContext: ViewerContext): Promise<void> {
|
|
6
|
+
// creator
|
|
7
|
+
const entityResult = await TestEntity.creator(viewerContext).setField('wat', 2).createAsync();
|
|
8
|
+
|
|
9
|
+
// updater
|
|
10
|
+
const updatedEntityResult = await TestEntity.updater(entityResult.enforceValue()).setField('wat', 3).updateAsync();
|
|
11
|
+
|
|
12
|
+
// deleter
|
|
13
|
+
await TestEntity.deleteAsync(updatedEntityResult.enforceValue());
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function testEnforcing(viewerContext: ViewerContext): Promise<void> {
|
|
17
|
+
// creator
|
|
18
|
+
const entity = await TestEntity.creator(viewerContext).setField('wat', 2).enforceCreateAsync();
|
|
19
|
+
const entity2 = await TestEntity.creator(viewerContext).setField('wat', 2).setField('who', 3).enforceCreateAsync();
|
|
20
|
+
const entity3 = await TestEntity.creator(viewerContext)
|
|
21
|
+
.setField('wat', 2)
|
|
22
|
+
.setField('who', 3)
|
|
23
|
+
.setField('who', 4)
|
|
24
|
+
.setField('who', 5)
|
|
25
|
+
.setField('who', 6)
|
|
26
|
+
.setField('who', 7)
|
|
27
|
+
.setField('who', 8)
|
|
28
|
+
.setField('who', 9)
|
|
29
|
+
.enforceCreateAsync();
|
|
30
|
+
|
|
31
|
+
// updater
|
|
32
|
+
const updatedEntity = await TestEntity.updater(entity).setField('wat', 3).enforceUpdateAsync();
|
|
33
|
+
const updatedEntity2 = await TestEntity.updater(entity2).setField('wat', 3).setField('who', 4).enforceUpdateAsync();
|
|
34
|
+
const updatedEntity3 = await TestEntity.updater(entity3)
|
|
35
|
+
.setField('wat', 3)
|
|
36
|
+
.setField('who', 4)
|
|
37
|
+
.setField('who', 5)
|
|
38
|
+
.setField('who', 6)
|
|
39
|
+
.setField('who', 7)
|
|
40
|
+
.setField('who', 8)
|
|
41
|
+
.setField('who', 9)
|
|
42
|
+
.enforceUpdateAsync();
|
|
43
|
+
|
|
44
|
+
// deleter
|
|
45
|
+
await TestEntity.enforceDeleteAsync(entity);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function testNoSetField(viewerContext: ViewerContext): Promise<void> {
|
|
49
|
+
// creator
|
|
50
|
+
const entity = await TestEntity.creator(viewerContext).enforceCreateAsync();
|
|
51
|
+
|
|
52
|
+
// updater
|
|
53
|
+
const updatedEntity = await TestEntity.updater(entity).enforceUpdateAsync();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function testEnforcingWithQueryContext(viewerContext: ViewerContext): Promise<void> {
|
|
57
|
+
// creator
|
|
58
|
+
const entity = await TestEntity.creator(viewerContext, queryContext).setField('wat', 2).enforceCreateAsync();
|
|
59
|
+
|
|
60
|
+
// updater
|
|
61
|
+
const updatedEntity = await TestEntity.updater(entity, queryContext).setField('wat', 3).enforceUpdateAsync();
|
|
62
|
+
|
|
63
|
+
// deleter
|
|
64
|
+
await TestEntity.enforceDeleteAsync(entity, queryContext);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function testAssociationLoader(): Promise<void> {
|
|
68
|
+
await this.associationLoader().loadAssociatedEntityAsync(
|
|
69
|
+
'another_id',
|
|
70
|
+
AnotherEntity,
|
|
71
|
+
queryContext
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
await entity.associationLoader().loadAssociatedEntityAsync(
|
|
75
|
+
'another_id',
|
|
76
|
+
AnotherEntity,
|
|
77
|
+
queryContext
|
|
78
|
+
)
|
|
79
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
|
|
3
|
+
import { ViewerContext } from '@expo/entity';
|
|
4
|
+
|
|
5
|
+
async function testWithAuthorizationResults(viewerContext: ViewerContext): Promise<void> {
|
|
6
|
+
// creator
|
|
7
|
+
const entityResult = await TestEntity.creator(viewerContext).withAuthorizationResults().setField('wat', 2).createAsync();
|
|
8
|
+
|
|
9
|
+
// updater
|
|
10
|
+
const updatedEntityResult = await TestEntity.updater(entityResult.enforceValue()).withAuthorizationResults().setField('wat', 3).updateAsync();
|
|
11
|
+
|
|
12
|
+
// deleter
|
|
13
|
+
await TestEntity.deleter(updatedEntityResult.enforceValue()).withAuthorizationResults().deleteAsync();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function testEnforcing(viewerContext: ViewerContext): Promise<void> {
|
|
17
|
+
// creator
|
|
18
|
+
const entity = await TestEntity.creator(viewerContext).enforcing().setField('wat', 2).createAsync();
|
|
19
|
+
const entity2 = await TestEntity.creator(viewerContext).enforcing().setField('wat', 2).setField('who', 3).createAsync();
|
|
20
|
+
const entity3 = await TestEntity.creator(viewerContext).enforcing()
|
|
21
|
+
.setField('wat', 2)
|
|
22
|
+
.setField('who', 3)
|
|
23
|
+
.setField('who', 4)
|
|
24
|
+
.setField('who', 5)
|
|
25
|
+
.setField('who', 6)
|
|
26
|
+
.setField('who', 7)
|
|
27
|
+
.setField('who', 8)
|
|
28
|
+
.setField('who', 9)
|
|
29
|
+
.createAsync();
|
|
30
|
+
|
|
31
|
+
// updater
|
|
32
|
+
const updatedEntity = await TestEntity.updater(entity).enforcing().setField('wat', 3).updateAsync();
|
|
33
|
+
const updatedEntity2 = await TestEntity.updater(entity2).enforcing().setField('wat', 3).setField('who', 4).updateAsync();
|
|
34
|
+
const updatedEntity3 = await TestEntity.updater(entity3).enforcing()
|
|
35
|
+
.setField('wat', 3)
|
|
36
|
+
.setField('who', 4)
|
|
37
|
+
.setField('who', 5)
|
|
38
|
+
.setField('who', 6)
|
|
39
|
+
.setField('who', 7)
|
|
40
|
+
.setField('who', 8)
|
|
41
|
+
.setField('who', 9)
|
|
42
|
+
.updateAsync();
|
|
43
|
+
|
|
44
|
+
// deleter
|
|
45
|
+
await TestEntity.deleter(entity).enforcing().deleteAsync();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function testNoSetField(viewerContext: ViewerContext): Promise<void> {
|
|
49
|
+
// creator
|
|
50
|
+
const entity = await TestEntity.creator(viewerContext).enforcing().createAsync();
|
|
51
|
+
|
|
52
|
+
// updater
|
|
53
|
+
const updatedEntity = await TestEntity.updater(entity).enforcing().updateAsync();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function testEnforcingWithQueryContext(viewerContext: ViewerContext): Promise<void> {
|
|
57
|
+
// creator
|
|
58
|
+
const entity = await TestEntity.creator(viewerContext, queryContext).enforcing().setField('wat', 2).createAsync();
|
|
59
|
+
|
|
60
|
+
// updater
|
|
61
|
+
const updatedEntity = await TestEntity.updater(entity, queryContext).enforcing().setField('wat', 3).updateAsync();
|
|
62
|
+
|
|
63
|
+
// deleter
|
|
64
|
+
await TestEntity.deleter(entity, queryContext).enforcing().deleteAsync();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function testAssociationLoader(): Promise<void> {
|
|
68
|
+
await this.associationLoader().withAuthorizationResults().loadAssociatedEntityAsync(
|
|
69
|
+
'another_id',
|
|
70
|
+
AnotherEntity,
|
|
71
|
+
queryContext
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
await entity.associationLoader().withAuthorizationResults().loadAssociatedEntityAsync(
|
|
75
|
+
'another_id',
|
|
76
|
+
AnotherEntity,
|
|
77
|
+
queryContext
|
|
78
|
+
)
|
|
79
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
|
|
3
|
+
async function testAsync(viewerContext: ViewerContext): Promise<void> {
|
|
4
|
+
const testTrigger = await TestTriggerEntity.createAsync(actorViewerContext, undefined, {
|
|
5
|
+
appId,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
await TestTriggerEntity.enforceDeleteAsync(testTrigger);
|
|
9
|
+
return testTrigger;
|
|
10
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
|
|
3
|
+
async function testAsync(viewerContext: ViewerContext): Promise<void> {
|
|
4
|
+
const testTrigger = await TestTriggerEntity.createAsync(actorViewerContext, undefined, {
|
|
5
|
+
appId,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
await TestTriggerEntity.deleter(testTrigger).enforcing().deleteAsync();
|
|
9
|
+
return testTrigger;
|
|
10
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { readdirSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
|
|
4
|
+
jest.autoMockOff();
|
|
5
|
+
const defineTest = require('jscodeshift/dist/testUtils').defineTest;
|
|
6
|
+
|
|
7
|
+
const fixtureDir = 'v0.39.0-v0.40.0';
|
|
8
|
+
const fixtureDirPath = join(__dirname, '..', '__testfixtures__', fixtureDir);
|
|
9
|
+
const fixtures = readdirSync(fixtureDirPath)
|
|
10
|
+
.filter((file) => file.endsWith('.input.ts'))
|
|
11
|
+
.map((file) => file.replace('.input.ts', ''));
|
|
12
|
+
|
|
13
|
+
for (const fixture of fixtures) {
|
|
14
|
+
const prefix = `${fixtureDir}/${fixture}`;
|
|
15
|
+
defineTest(__dirname, 'v0.39.0-v0.40.0', null, prefix, { parser: 'ts' });
|
|
16
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { API, Collection, FileInfo, Options } from 'jscodeshift';
|
|
2
|
+
|
|
3
|
+
function transformEnforcingEntityChainMethod(
|
|
4
|
+
j: API['jscodeshift'],
|
|
5
|
+
root: Collection<any>,
|
|
6
|
+
type: 'enforcing' | 'withAuthorizationResults',
|
|
7
|
+
crudType: 'creator' | 'updater',
|
|
8
|
+
methodBefore: string,
|
|
9
|
+
methodAfter: string,
|
|
10
|
+
): void {
|
|
11
|
+
// Find all entity creator expressions of the form
|
|
12
|
+
// `TestEntity.creator(viewerContext).setField('wat', 2).enforceCreateAsync()`
|
|
13
|
+
root
|
|
14
|
+
.find(j.CallExpression, {
|
|
15
|
+
callee: {
|
|
16
|
+
type: 'MemberExpression',
|
|
17
|
+
property: {
|
|
18
|
+
name: methodBefore,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
.forEach((path) => {
|
|
23
|
+
const enforceCreateAsyncCallExpression = path.node; // TestEntity.creator(viewerContext).setField('wat', 2).enforceCreateAsync()
|
|
24
|
+
const enforceCreateAsyncCallee = enforceCreateAsyncCallExpression.callee; // TestEntity.creator(viewerContext).setField('wat', 2).enforceCreateAsync
|
|
25
|
+
if (enforceCreateAsyncCallee.type !== 'MemberExpression') {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (enforceCreateAsyncCallee.property.type !== 'Identifier') {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// traverse in until we find the first non-setField call
|
|
34
|
+
let lastCallee = enforceCreateAsyncCallee;
|
|
35
|
+
while (true) {
|
|
36
|
+
// TestEntity.creator(viewerContext).setField('wat', 2)
|
|
37
|
+
const maybeSetFieldObjectCallExpression = lastCallee.object;
|
|
38
|
+
if (maybeSetFieldObjectCallExpression.type !== 'CallExpression') {
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// TestEntity.creator(viewerContext).setField
|
|
43
|
+
const maybeSetFieldObjectCallee = maybeSetFieldObjectCallExpression.callee;
|
|
44
|
+
if (maybeSetFieldObjectCallee.type !== 'MemberExpression') {
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const maybeSetFieldObjectCalleeProperty = maybeSetFieldObjectCallee.property;
|
|
49
|
+
if (maybeSetFieldObjectCalleeProperty.type !== 'Identifier') {
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (maybeSetFieldObjectCalleeProperty.name === 'setField') {
|
|
54
|
+
lastCallee = maybeSetFieldObjectCallee;
|
|
55
|
+
} else {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// TestEntity.creator(viewerContext)
|
|
61
|
+
const maybeCreatorCallExpression = lastCallee.object;
|
|
62
|
+
if (maybeCreatorCallExpression.type !== 'CallExpression') {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (
|
|
66
|
+
maybeCreatorCallExpression.callee.type !== 'MemberExpression' ||
|
|
67
|
+
maybeCreatorCallExpression.callee.property.type !== 'Identifier' ||
|
|
68
|
+
maybeCreatorCallExpression.callee.property.name !== crudType
|
|
69
|
+
) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// TestEntity.creator(viewerContext).enforcing()
|
|
74
|
+
const newCreatorCallExpression = j.callExpression(
|
|
75
|
+
j.memberExpression(maybeCreatorCallExpression, j.identifier(type)),
|
|
76
|
+
[],
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// TestEntity.creator(viewerContext).enforcing().setField('wat', 2).createAsync()
|
|
80
|
+
lastCallee.object = newCreatorCallExpression;
|
|
81
|
+
|
|
82
|
+
// change enforceCreateAsync to createAsync at the end so if this returns early it doesn't mutate
|
|
83
|
+
enforceCreateAsyncCallee.property.name = methodAfter;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function transformEnforcingEntityDeleteMethod(
|
|
88
|
+
j: API['jscodeshift'],
|
|
89
|
+
root: Collection<any>,
|
|
90
|
+
type: 'enforcing' | 'withAuthorizationResults',
|
|
91
|
+
methodBefore: string,
|
|
92
|
+
methodAfter: string,
|
|
93
|
+
): void {
|
|
94
|
+
// Find all entity creator expressions of the form
|
|
95
|
+
// `TestEntity.enforceDeleteAsync(entity)`
|
|
96
|
+
root
|
|
97
|
+
.find(j.CallExpression, {
|
|
98
|
+
callee: {
|
|
99
|
+
type: 'MemberExpression',
|
|
100
|
+
property: {
|
|
101
|
+
name: methodBefore,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
.forEach((path) => {
|
|
106
|
+
const enforceDeleteAsyncCallExpression = path.node; // TestEntity.enforceDeleteAsync(entity)
|
|
107
|
+
const args = enforceDeleteAsyncCallExpression.arguments; // [entity]
|
|
108
|
+
enforceDeleteAsyncCallExpression.arguments = [];
|
|
109
|
+
const enforceDeleteAsyncCallee = enforceDeleteAsyncCallExpression.callee; // TestEntity.enforceDeleteAsync
|
|
110
|
+
if (enforceDeleteAsyncCallee.type !== 'MemberExpression') {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// change enforceDeleteAsync to deleteAsync
|
|
115
|
+
if (enforceDeleteAsyncCallee.property.type !== 'Identifier') {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
enforceDeleteAsyncCallee.property.name = methodAfter;
|
|
119
|
+
|
|
120
|
+
enforceDeleteAsyncCallee.object = j.callExpression(
|
|
121
|
+
j.memberExpression(
|
|
122
|
+
j.callExpression(
|
|
123
|
+
j.memberExpression(enforceDeleteAsyncCallee.object, j.identifier('deleter')),
|
|
124
|
+
args,
|
|
125
|
+
),
|
|
126
|
+
j.identifier(type),
|
|
127
|
+
),
|
|
128
|
+
[],
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function transformAssociationLoaderMethod(j: API['jscodeshift'], root: Collection<any>): void {
|
|
134
|
+
// Find all entity associationLoader expressions of the form
|
|
135
|
+
// `this.associationLoader()`
|
|
136
|
+
root
|
|
137
|
+
.find(j.CallExpression, {
|
|
138
|
+
callee: {
|
|
139
|
+
type: 'MemberExpression',
|
|
140
|
+
property: {
|
|
141
|
+
name: 'associationLoader',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
})
|
|
145
|
+
.forEach((path) => {
|
|
146
|
+
const associationLoaderCallExpression = path.node; // this.associationLoader()
|
|
147
|
+
|
|
148
|
+
// replace with this.associationLoader().withAuthorizationResults()
|
|
149
|
+
path.replace(
|
|
150
|
+
j.callExpression(
|
|
151
|
+
j.memberExpression(
|
|
152
|
+
associationLoaderCallExpression,
|
|
153
|
+
j.identifier('withAuthorizationResults'),
|
|
154
|
+
),
|
|
155
|
+
[],
|
|
156
|
+
),
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export default function transformer(file: FileInfo, api: API, _options: Options): string {
|
|
162
|
+
const j = api.jscodeshift;
|
|
163
|
+
const root = j.withParser('ts')(file.source);
|
|
164
|
+
|
|
165
|
+
// do authorization results first since it uses the same detection pattern as enforcing post-transform (i.e. it looks for createAsync)
|
|
166
|
+
transformEnforcingEntityChainMethod(
|
|
167
|
+
j,
|
|
168
|
+
root,
|
|
169
|
+
'withAuthorizationResults',
|
|
170
|
+
'creator',
|
|
171
|
+
'createAsync',
|
|
172
|
+
'createAsync',
|
|
173
|
+
);
|
|
174
|
+
transformEnforcingEntityChainMethod(
|
|
175
|
+
j,
|
|
176
|
+
root,
|
|
177
|
+
'withAuthorizationResults',
|
|
178
|
+
'updater',
|
|
179
|
+
'updateAsync',
|
|
180
|
+
'updateAsync',
|
|
181
|
+
);
|
|
182
|
+
transformEnforcingEntityDeleteMethod(
|
|
183
|
+
j,
|
|
184
|
+
root,
|
|
185
|
+
'withAuthorizationResults',
|
|
186
|
+
'deleteAsync',
|
|
187
|
+
'deleteAsync',
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
// now do enforcing
|
|
191
|
+
transformEnforcingEntityChainMethod(
|
|
192
|
+
j,
|
|
193
|
+
root,
|
|
194
|
+
'enforcing',
|
|
195
|
+
'creator',
|
|
196
|
+
'enforceCreateAsync',
|
|
197
|
+
'createAsync',
|
|
198
|
+
);
|
|
199
|
+
transformEnforcingEntityChainMethod(
|
|
200
|
+
j,
|
|
201
|
+
root,
|
|
202
|
+
'enforcing',
|
|
203
|
+
'updater',
|
|
204
|
+
'enforceUpdateAsync',
|
|
205
|
+
'updateAsync',
|
|
206
|
+
);
|
|
207
|
+
transformEnforcingEntityDeleteMethod(j, root, 'enforcing', 'enforceDeleteAsync', 'deleteAsync');
|
|
208
|
+
|
|
209
|
+
// association loader
|
|
210
|
+
transformAssociationLoaderMethod(j, root);
|
|
211
|
+
|
|
212
|
+
return root.toSource();
|
|
213
|
+
}
|