zenstack 1.0.0-alpha.99 → 1.0.0-beta.10
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 +65 -24
- package/cli/cli-util.d.ts +4 -1
- package/cli/cli-util.js +63 -9
- package/cli/cli-util.js.map +1 -1
- package/cli/config.js +39 -13
- package/cli/config.js.map +1 -1
- package/cli/index.js +1 -6
- package/cli/index.js.map +1 -1
- package/cli/plugin-runner.d.ts +2 -1
- package/cli/plugin-runner.js +106 -48
- package/cli/plugin-runner.js.map +1 -1
- package/language-server/constants.d.ts +0 -4
- package/language-server/constants.js +1 -14
- package/language-server/constants.js.map +1 -1
- package/language-server/utils.d.ts +1 -5
- package/language-server/utils.js +3 -20
- package/language-server/utils.js.map +1 -1
- package/language-server/validator/datamodel-validator.d.ts +7 -0
- package/language-server/validator/datamodel-validator.js +71 -21
- package/language-server/validator/datamodel-validator.js.map +1 -1
- package/language-server/validator/expression-validator.js +44 -7
- package/language-server/validator/expression-validator.js.map +1 -1
- package/language-server/validator/function-decl-validator.d.ts +9 -0
- package/language-server/validator/function-decl-validator.js +15 -0
- package/language-server/validator/function-decl-validator.js.map +1 -0
- package/language-server/validator/function-invocation-validator.js +31 -5
- package/language-server/validator/function-invocation-validator.js.map +1 -1
- package/language-server/validator/schema-validator.d.ts +4 -1
- package/language-server/validator/schema-validator.js +25 -5
- package/language-server/validator/schema-validator.js.map +1 -1
- package/language-server/validator/utils.d.ts +4 -4
- package/language-server/validator/utils.js +10 -1
- package/language-server/validator/utils.js.map +1 -1
- package/language-server/validator/zmodel-validator.d.ts +4 -1
- package/language-server/validator/zmodel-validator.js +13 -4
- package/language-server/validator/zmodel-validator.js.map +1 -1
- package/language-server/zmodel-code-action.d.ts +2 -1
- package/language-server/zmodel-code-action.js +19 -10
- package/language-server/zmodel-code-action.js.map +1 -1
- package/language-server/zmodel-definition.d.ts +7 -0
- package/language-server/zmodel-definition.js +31 -0
- package/language-server/zmodel-definition.js.map +1 -0
- package/language-server/zmodel-formatter.js +2 -2
- package/language-server/zmodel-formatter.js.map +1 -1
- package/language-server/zmodel-linker.d.ts +2 -0
- package/language-server/zmodel-linker.js +71 -7
- package/language-server/zmodel-linker.js.map +1 -1
- package/language-server/zmodel-module.js +4 -1
- package/language-server/zmodel-module.js.map +1 -1
- package/language-server/zmodel-scope.d.ts +7 -1
- package/language-server/zmodel-scope.js +57 -1
- package/language-server/zmodel-scope.js.map +1 -1
- package/package.json +19 -21
- package/plugins/access-policy/expression-writer.js +71 -25
- package/plugins/access-policy/expression-writer.js.map +1 -1
- package/plugins/access-policy/policy-guard-generator.js +107 -73
- package/plugins/access-policy/policy-guard-generator.js.map +1 -1
- package/plugins/access-policy/utils.d.ts +2 -2
- package/plugins/access-policy/utils.js +2 -2
- package/plugins/access-policy/utils.js.map +1 -1
- package/plugins/model-meta/index.js +35 -31
- package/plugins/model-meta/index.js.map +1 -1
- package/plugins/plugin-utils.d.ts +4 -4
- package/plugins/plugin-utils.js +28 -18
- package/plugins/plugin-utils.js.map +1 -1
- package/plugins/prisma/index.d.ts +1 -1
- package/plugins/prisma/prisma-builder.d.ts +6 -3
- package/plugins/prisma/prisma-builder.js +29 -8
- package/plugins/prisma/prisma-builder.js.map +1 -1
- package/plugins/prisma/schema-generator.d.ts +4 -1
- package/plugins/prisma/schema-generator.js +149 -32
- package/plugins/prisma/schema-generator.js.map +1 -1
- package/plugins/zod/generator.js +171 -22
- package/plugins/zod/generator.js.map +1 -1
- package/plugins/zod/index.d.ts +1 -1
- package/plugins/zod/transformer.d.ts +6 -6
- package/plugins/zod/transformer.js +168 -108
- package/plugins/zod/transformer.js.map +1 -1
- package/plugins/zod/types.d.ts +2 -0
- package/plugins/zod/utils/schema-gen.d.ts +3 -0
- package/plugins/zod/utils/schema-gen.js +178 -0
- package/plugins/zod/utils/schema-gen.js.map +1 -0
- package/res/starter.zmodel +4 -4
- package/res/stdlib.zmodel +176 -90
- package/telemetry.d.ts +2 -1
- package/telemetry.js +5 -3
- package/telemetry.js.map +1 -1
- package/utils/ast-utils.d.ts +10 -3
- package/utils/ast-utils.js +91 -8
- package/utils/ast-utils.js.map +1 -1
- package/utils/pkg-utils.js +1 -1
- package/utils/pkg-utils.js.map +1 -1
- package/utils/typescript-expression-transformer.d.ts +53 -0
- package/utils/typescript-expression-transformer.js +295 -0
- package/utils/typescript-expression-transformer.js.map +1 -0
- package/utils/version-utils.js +1 -0
- package/utils/version-utils.js.map +1 -1
- package/plugins/access-policy/typescript-expression-transformer.d.ts +0 -28
- package/plugins/access-policy/typescript-expression-transformer.js +0 -121
- package/plugins/access-policy/typescript-expression-transformer.js.map +0 -1
- package/plugins/access-policy/zod-schema-generator.d.ts +0 -12
- package/plugins/access-policy/zod-schema-generator.js +0 -157
- package/plugins/access-policy/zod-schema-generator.js.map +0 -1
package/cli/plugin-runner.js
CHANGED
|
@@ -13,17 +13,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.PluginRunner = void 0;
|
|
16
|
-
const internals_1 = require("@prisma/internals");
|
|
17
16
|
const ast_1 = require("@zenstackhq/language/ast");
|
|
18
17
|
const sdk_1 = require("@zenstackhq/sdk");
|
|
19
18
|
const colors_1 = __importDefault(require("colors"));
|
|
20
19
|
const fs_1 = __importDefault(require("fs"));
|
|
21
20
|
const ora_1 = __importDefault(require("ora"));
|
|
22
21
|
const path_1 = __importDefault(require("path"));
|
|
22
|
+
const plugin_utils_1 = require("../plugins/plugin-utils");
|
|
23
23
|
const telemetry_1 = __importDefault(require("../telemetry"));
|
|
24
|
+
const version_utils_1 = require("../utils/version-utils");
|
|
24
25
|
const config_1 = require("./config");
|
|
25
26
|
/**
|
|
26
|
-
* ZenStack
|
|
27
|
+
* ZenStack plugin runner
|
|
27
28
|
*/
|
|
28
29
|
class PluginRunner {
|
|
29
30
|
/**
|
|
@@ -31,82 +32,138 @@ class PluginRunner {
|
|
|
31
32
|
*/
|
|
32
33
|
run(context) {
|
|
33
34
|
return __awaiter(this, void 0, void 0, function* () {
|
|
34
|
-
const version =
|
|
35
|
+
const version = (0, version_utils_1.getVersion)();
|
|
35
36
|
console.log(colors_1.default.bold(`⌛️ ZenStack CLI v${version}, running plugins`));
|
|
37
|
+
(0, plugin_utils_1.ensureDefaultOutputFolder)();
|
|
36
38
|
const plugins = [];
|
|
37
39
|
const pluginDecls = context.schema.declarations.filter((d) => (0, ast_1.isPlugin)(d));
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
40
|
+
let prismaOutput = (0, sdk_1.resolvePath)('./prisma/schema.prisma', { schemaPath: context.schemaPath, name: '' });
|
|
41
|
+
for (const pluginDecl of pluginDecls) {
|
|
42
|
+
const pluginProvider = this.getPluginProvider(pluginDecl);
|
|
43
|
+
if (!pluginProvider) {
|
|
44
|
+
console.error(`Plugin ${pluginDecl.name} has invalid provider option`);
|
|
45
|
+
throw new sdk_1.PluginError('', `Plugin ${pluginDecl.name} has invalid provider option`);
|
|
46
|
+
}
|
|
47
|
+
const pluginModulePath = this.getPluginModulePath(pluginProvider);
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
|
+
let pluginModule;
|
|
50
|
+
try {
|
|
51
|
+
pluginModule = require(pluginModulePath);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
console.error(`Unable to load plugin module ${pluginProvider}: ${pluginModulePath}, ${err}`);
|
|
55
|
+
throw new sdk_1.PluginError('', `Unable to load plugin module ${pluginProvider}`);
|
|
56
|
+
}
|
|
57
|
+
if (!pluginModule.default || typeof pluginModule.default !== 'function') {
|
|
58
|
+
console.error(`Plugin provider ${pluginProvider} is missing a default function export`);
|
|
59
|
+
throw new sdk_1.PluginError('', `Plugin provider ${pluginProvider} is missing a default function export`);
|
|
60
|
+
}
|
|
61
|
+
const dependencies = this.getPluginDependencies(pluginModule);
|
|
62
|
+
const pluginName = this.getPluginName(pluginModule, pluginProvider);
|
|
63
|
+
const options = { schemaPath: context.schemaPath, name: pluginName };
|
|
64
|
+
pluginDecl.fields.forEach((f) => {
|
|
65
|
+
var _a;
|
|
66
|
+
const value = (_a = (0, sdk_1.getLiteral)(f.value)) !== null && _a !== void 0 ? _a : (0, sdk_1.getLiteralArray)(f.value);
|
|
67
|
+
if (value === undefined) {
|
|
68
|
+
throw new sdk_1.PluginError(pluginName, `Invalid option value for ${f.name}`);
|
|
64
69
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
options[f.name] = value;
|
|
71
|
+
});
|
|
72
|
+
plugins.push({
|
|
73
|
+
name: pluginName,
|
|
74
|
+
provider: pluginProvider,
|
|
75
|
+
dependencies,
|
|
76
|
+
options,
|
|
77
|
+
run: pluginModule.default,
|
|
78
|
+
module: pluginModule,
|
|
79
|
+
});
|
|
80
|
+
if (pluginProvider === '@core/prisma' && typeof options.output === 'string') {
|
|
81
|
+
// record custom prisma output path
|
|
82
|
+
prismaOutput = (0, sdk_1.resolvePath)(options.output, options);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// make sure prerequisites are included
|
|
86
|
+
const corePlugins = [
|
|
87
|
+
{ provider: '@core/prisma' },
|
|
88
|
+
{ provider: '@core/model-meta' },
|
|
89
|
+
{ provider: '@core/access-policy' },
|
|
90
|
+
];
|
|
91
|
+
if ((0, sdk_1.getDataModels)(context.schema).some((model) => (0, sdk_1.hasValidationAttributes)(model))) {
|
|
92
|
+
// '@core/zod' plugin is auto-enabled if there're validation rules
|
|
93
|
+
corePlugins.push({ provider: '@core/zod', options: { modelOnly: true } });
|
|
94
|
+
}
|
|
95
|
+
// core plugins introduced by dependencies
|
|
96
|
+
plugins
|
|
97
|
+
.flatMap((p) => p.dependencies)
|
|
98
|
+
.forEach((dep) => {
|
|
99
|
+
if (dep.startsWith('@core/')) {
|
|
100
|
+
const existing = corePlugins.find((p) => p.provider === dep);
|
|
101
|
+
if (existing) {
|
|
102
|
+
// reset options to default
|
|
103
|
+
existing.options = undefined;
|
|
68
104
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
provider:
|
|
72
|
-
run: pluginModule.default,
|
|
73
|
-
options,
|
|
74
|
-
});
|
|
75
|
-
if (pluginProvider === '@core/prisma' && options.output) {
|
|
76
|
-
// record custom prisma output path
|
|
77
|
-
prismaOutput = options.output;
|
|
105
|
+
else {
|
|
106
|
+
// add core dependency
|
|
107
|
+
corePlugins.push({ provider: dep });
|
|
78
108
|
}
|
|
79
109
|
}
|
|
110
|
+
});
|
|
111
|
+
for (const corePlugin of corePlugins.reverse()) {
|
|
112
|
+
const existingIdx = plugins.findIndex((p) => p.provider === corePlugin.provider);
|
|
113
|
+
if (existingIdx >= 0) {
|
|
114
|
+
// shift the plugin to the front
|
|
115
|
+
const existing = plugins[existingIdx];
|
|
116
|
+
plugins.splice(existingIdx, 1);
|
|
117
|
+
plugins.unshift(existing);
|
|
118
|
+
}
|
|
80
119
|
else {
|
|
81
|
-
// synthesize a plugin
|
|
82
|
-
const pluginModule = require(this.getPluginModulePath(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
120
|
+
// synthesize a plugin and insert front
|
|
121
|
+
const pluginModule = require(this.getPluginModulePath(corePlugin.provider));
|
|
122
|
+
const pluginName = this.getPluginName(pluginModule, corePlugin.provider);
|
|
123
|
+
plugins.unshift({
|
|
124
|
+
name: pluginName,
|
|
125
|
+
provider: corePlugin.provider,
|
|
126
|
+
dependencies: [],
|
|
127
|
+
options: Object.assign({ schemaPath: context.schemaPath, name: pluginName }, corePlugin.options),
|
|
86
128
|
run: pluginModule.default,
|
|
87
|
-
|
|
129
|
+
module: pluginModule,
|
|
88
130
|
});
|
|
89
131
|
}
|
|
90
132
|
}
|
|
133
|
+
// check dependencies
|
|
134
|
+
for (const plugin of plugins) {
|
|
135
|
+
for (const dep of plugin.dependencies) {
|
|
136
|
+
if (!plugins.find((p) => p.provider === dep)) {
|
|
137
|
+
console.error(`Plugin ${plugin.provider} depends on "${dep}" but it's not declared`);
|
|
138
|
+
throw new sdk_1.PluginError(plugin.name, `Plugin ${plugin.provider} depends on "${dep}" but it's not declared`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
91
142
|
const warnings = [];
|
|
92
143
|
let dmmf = undefined;
|
|
93
144
|
for (const { name, provider, run, options } of plugins) {
|
|
145
|
+
// const start = Date.now();
|
|
94
146
|
yield this.runPlugin(name, run, context, options, dmmf, warnings);
|
|
147
|
+
// console.log(`✅ Plugin ${colors.bold(name)} (${provider}) completed in ${Date.now() - start}ms`);
|
|
95
148
|
if (provider === '@core/prisma') {
|
|
96
149
|
// load prisma DMMF
|
|
97
|
-
dmmf = yield (0,
|
|
150
|
+
dmmf = yield (0, sdk_1.getDMMF)({
|
|
98
151
|
datamodel: fs_1.default.readFileSync(prismaOutput, { encoding: 'utf-8' }),
|
|
99
152
|
});
|
|
100
153
|
}
|
|
101
154
|
}
|
|
102
155
|
console.log(colors_1.default.green(colors_1.default.bold('\n👻 All plugins completed successfully!')));
|
|
103
156
|
warnings.forEach((w) => console.warn(colors_1.default.yellow(w)));
|
|
157
|
+
console.log(`Don't forget to restart your dev server to let the changes take effect.`);
|
|
104
158
|
});
|
|
105
159
|
}
|
|
106
160
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
107
161
|
getPluginName(pluginModule, pluginProvider) {
|
|
108
162
|
return typeof pluginModule.name === 'string' ? pluginModule.name : pluginProvider;
|
|
109
163
|
}
|
|
164
|
+
getPluginDependencies(pluginModule) {
|
|
165
|
+
return Array.isArray(pluginModule.dependencies) ? pluginModule.dependencies : [];
|
|
166
|
+
}
|
|
110
167
|
getPluginProvider(plugin) {
|
|
111
168
|
const providerField = plugin.fields.find((f) => f.name === 'provider');
|
|
112
169
|
return (0, sdk_1.getLiteral)(providerField === null || providerField === void 0 ? void 0 : providerField.value);
|
|
@@ -117,6 +174,7 @@ class PluginRunner {
|
|
|
117
174
|
try {
|
|
118
175
|
yield telemetry_1.default.trackSpan('cli:plugin:start', 'cli:plugin:complete', 'cli:plugin:error', {
|
|
119
176
|
plugin: name,
|
|
177
|
+
options,
|
|
120
178
|
}, () => __awaiter(this, void 0, void 0, function* () {
|
|
121
179
|
let result = run(context.schema, options, dmmf, config_1.config);
|
|
122
180
|
if (result instanceof Promise) {
|
package/cli/plugin-runner.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-runner.js","sourceRoot":"","sources":["../../src/cli/plugin-runner.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"plugin-runner.js","sourceRoot":"","sources":["../../src/cli/plugin-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,7 +20,3 @@ export declare const PLUGIN_MODULE_NAME = "plugin.zmodel";
|
|
|
20
20
|
export declare enum IssueCodes {
|
|
21
21
|
MissingOppositeRelation = "miss-opposite-relation"
|
|
22
22
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Filter operation function names (mapped to Prisma filter operators)
|
|
25
|
-
*/
|
|
26
|
-
export declare const FILTER_OPERATOR_FUNCTIONS: string[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.IssueCodes = exports.PLUGIN_MODULE_NAME = exports.STD_LIB_MODULE_NAME = exports.SCALAR_TYPES = exports.SUPPORTED_PROVIDERS = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Supported Prisma db providers
|
|
6
6
|
*/
|
|
@@ -24,17 +24,4 @@ var IssueCodes;
|
|
|
24
24
|
(function (IssueCodes) {
|
|
25
25
|
IssueCodes["MissingOppositeRelation"] = "miss-opposite-relation";
|
|
26
26
|
})(IssueCodes = exports.IssueCodes || (exports.IssueCodes = {}));
|
|
27
|
-
/**
|
|
28
|
-
* Filter operation function names (mapped to Prisma filter operators)
|
|
29
|
-
*/
|
|
30
|
-
exports.FILTER_OPERATOR_FUNCTIONS = [
|
|
31
|
-
'contains',
|
|
32
|
-
'search',
|
|
33
|
-
'startsWith',
|
|
34
|
-
'endsWith',
|
|
35
|
-
'has',
|
|
36
|
-
'hasEvery',
|
|
37
|
-
'hasSome',
|
|
38
|
-
'isEmpty',
|
|
39
|
-
];
|
|
40
27
|
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/language-server/constants.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACU,QAAA,mBAAmB,GAAG,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;AAEjG;;GAEG;AACU,QAAA,YAAY,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AAE5G;;GAEG;AACU,QAAA,mBAAmB,GAAG,eAAe,CAAC;AAEnD;;GAEG;AACU,QAAA,kBAAkB,GAAG,eAAe,CAAC;AAElD;;GAEG;AACH,IAAY,UAEX;AAFD,WAAY,UAAU;IAClB,gEAAkD,CAAA;AACtD,CAAC,EAFW,UAAU,GAAV,kBAAU,KAAV,kBAAU,QAErB
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/language-server/constants.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACU,QAAA,mBAAmB,GAAG,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;AAEjG;;GAEG;AACU,QAAA,YAAY,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AAE5G;;GAEG;AACU,QAAA,mBAAmB,GAAG,eAAe,CAAC;AAEnD;;GAEG;AACU,QAAA,kBAAkB,GAAG,eAAe,CAAC;AAElD;;GAEG;AACH,IAAY,UAEX;AAFD,WAAY,UAAU;IAClB,gEAAkD,CAAA;AACtD,CAAC,EAFW,UAAU,GAAV,kBAAU,KAAV,kBAAU,QAErB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AstNode } from 'langium';
|
|
2
1
|
import { DataModel, DataModelField, Model } from '@zenstackhq/language/ast';
|
|
2
|
+
import { AstNode } from 'langium';
|
|
3
3
|
/**
|
|
4
4
|
* Gets the toplevel Model containing the given node.
|
|
5
5
|
*/
|
|
@@ -8,10 +8,6 @@ export declare function getContainingModel(node: AstNode | undefined): Model | n
|
|
|
8
8
|
* Returns if the given node is declared in stdlib.
|
|
9
9
|
*/
|
|
10
10
|
export declare function isFromStdlib(node: AstNode): boolean;
|
|
11
|
-
/**
|
|
12
|
-
* Gets id fields declared at the data model level
|
|
13
|
-
*/
|
|
14
|
-
export declare function getIdFields(model: DataModel): DataModelField[];
|
|
15
11
|
/**
|
|
16
12
|
* Gets lists of unique fields declared at the data model level
|
|
17
13
|
*/
|
package/language-server/utils.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getUniqueFields = exports.
|
|
4
|
-
const constants_1 = require("./constants");
|
|
3
|
+
exports.getUniqueFields = exports.isFromStdlib = exports.getContainingModel = void 0;
|
|
5
4
|
const ast_1 = require("@zenstackhq/language/ast");
|
|
6
5
|
const sdk_1 = require("@zenstackhq/sdk");
|
|
6
|
+
const constants_1 = require("./constants");
|
|
7
7
|
/**
|
|
8
8
|
* Gets the toplevel Model containing the given node.
|
|
9
9
|
*/
|
|
@@ -22,28 +22,11 @@ function isFromStdlib(node) {
|
|
|
22
22
|
return !!model && !!model.$document && model.$document.uri.path.endsWith(constants_1.STD_LIB_MODULE_NAME);
|
|
23
23
|
}
|
|
24
24
|
exports.isFromStdlib = isFromStdlib;
|
|
25
|
-
/**
|
|
26
|
-
* Gets id fields declared at the data model level
|
|
27
|
-
*/
|
|
28
|
-
function getIdFields(model) {
|
|
29
|
-
const idAttr = model.attributes.find((attr) => { var _a; return ((_a = attr.decl.ref) === null || _a === void 0 ? void 0 : _a.name) === '@@id'; });
|
|
30
|
-
if (!idAttr) {
|
|
31
|
-
return [];
|
|
32
|
-
}
|
|
33
|
-
const fieldsArg = idAttr.args.find((a) => { var _a; return ((_a = a.$resolvedParam) === null || _a === void 0 ? void 0 : _a.name) === 'fields'; });
|
|
34
|
-
if (!fieldsArg || !(0, ast_1.isArrayExpr)(fieldsArg.value)) {
|
|
35
|
-
return [];
|
|
36
|
-
}
|
|
37
|
-
return fieldsArg.value.items
|
|
38
|
-
.filter((item) => (0, ast_1.isReferenceExpr)(item))
|
|
39
|
-
.map((item) => (0, sdk_1.resolved)(item.target));
|
|
40
|
-
}
|
|
41
|
-
exports.getIdFields = getIdFields;
|
|
42
25
|
/**
|
|
43
26
|
* Gets lists of unique fields declared at the data model level
|
|
44
27
|
*/
|
|
45
28
|
function getUniqueFields(model) {
|
|
46
|
-
const uniqueAttrs = model.attributes.filter((attr) => { var _a; return ((_a = attr.decl.ref) === null || _a === void 0 ? void 0 : _a.name) === '@@unique'; });
|
|
29
|
+
const uniqueAttrs = model.attributes.filter((attr) => { var _a, _b; return ((_a = attr.decl.ref) === null || _a === void 0 ? void 0 : _a.name) === '@@unique' || ((_b = attr.decl.ref) === null || _b === void 0 ? void 0 : _b.name) === '@@id'; });
|
|
47
30
|
return uniqueAttrs.map((uniqueAttr) => {
|
|
48
31
|
const fieldsArg = uniqueAttr.args.find((a) => { var _a; return ((_a = a.$resolvedParam) === null || _a === void 0 ? void 0 : _a.name) === 'fields'; });
|
|
49
32
|
if (!fieldsArg || !(0, ast_1.isArrayExpr)(fieldsArg.value)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/language-server/utils.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/language-server/utils.ts"],"names":[],"mappings":";;;AAAA,kDAQkC;AAClC,yCAA2C;AAE3C,2CAAkD;AAElD;;GAEG;AACH,SAAgB,kBAAkB,CAAC,IAAyB;IACxD,IAAI,CAAC,IAAI,EAAE;QACP,OAAO,IAAI,CAAC;KACf;IACD,OAAO,IAAA,aAAO,EAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACtE,CAAC;AALD,gDAKC;AAED;;GAEG;AACH,SAAgB,YAAY,CAAC,IAAa;IACtC,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,+BAAmB,CAAC,CAAC;AAClG,CAAC;AAHD,oCAGC;AAED;;GAEG;AACH,SAAgB,eAAe,CAAC,KAAgB;IAC5C,MAAM,WAAW,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CACvC,CAAC,IAAI,EAAE,EAAE,eAAC,OAAA,CAAA,MAAA,IAAI,CAAC,IAAI,CAAC,GAAG,0CAAE,IAAI,MAAK,UAAU,IAAI,CAAA,MAAA,IAAI,CAAC,IAAI,CAAC,GAAG,0CAAE,IAAI,MAAK,MAAM,CAAA,EAAA,CACjF,CAAC;IACF,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;QAClC,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,WAAC,OAAA,CAAA,MAAA,CAAC,CAAC,cAAc,0CAAE,IAAI,MAAK,QAAQ,CAAA,EAAA,CAAC,CAAC;QACnF,IAAI,CAAC,SAAS,IAAI,CAAC,IAAA,iBAAW,EAAC,SAAS,CAAC,KAAK,CAAC,EAAE;YAC7C,OAAO,EAAE,CAAC;SACb;QAED,OAAO,SAAS,CAAC,KAAK,CAAC,KAAK;aACvB,MAAM,CAAC,CAAC,IAAI,EAAyB,EAAE,CAAC,IAAA,qBAAe,EAAC,IAAI,CAAC,CAAC;aAC9D,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,cAAQ,EAAC,IAAI,CAAC,MAAM,CAAmB,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;AACP,CAAC;AAdD,0CAcC"}
|
|
@@ -12,4 +12,11 @@ export default class DataModelValidator implements AstValidator<DataModel> {
|
|
|
12
12
|
private parseRelation;
|
|
13
13
|
private isSelfRelation;
|
|
14
14
|
private validateRelationField;
|
|
15
|
+
private validateBaseAbstractModel;
|
|
16
|
+
}
|
|
17
|
+
export interface MissingOppositeRelationData {
|
|
18
|
+
relationDataModelName: string;
|
|
19
|
+
relationFieldName: string;
|
|
20
|
+
relationFieldDocUri: string;
|
|
21
|
+
dataModelName: string;
|
|
15
22
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const ast_1 = require("@zenstackhq/language/ast");
|
|
4
4
|
const sdk_1 = require("@zenstackhq/sdk");
|
|
5
|
+
const langium_1 = require("langium");
|
|
5
6
|
const constants_1 = require("../constants");
|
|
6
7
|
const utils_1 = require("../utils");
|
|
7
8
|
const utils_2 = require("./utils");
|
|
@@ -10,19 +11,25 @@ const utils_2 = require("./utils");
|
|
|
10
11
|
*/
|
|
11
12
|
class DataModelValidator {
|
|
12
13
|
validate(dm, accept) {
|
|
13
|
-
|
|
14
|
+
this.validateBaseAbstractModel(dm, accept);
|
|
15
|
+
(0, utils_2.validateDuplicatedDeclarations)(dm.$resolvedFields, accept);
|
|
14
16
|
this.validateAttributes(dm, accept);
|
|
15
17
|
this.validateFields(dm, accept);
|
|
16
18
|
}
|
|
17
19
|
validateFields(dm, accept) {
|
|
18
|
-
const idFields = dm.
|
|
19
|
-
const
|
|
20
|
-
|
|
20
|
+
const idFields = dm.$resolvedFields.filter((f) => f.attributes.find((attr) => { var _a; return ((_a = attr.decl.ref) === null || _a === void 0 ? void 0 : _a.name) === '@id'; }));
|
|
21
|
+
const uniqueFields = dm.$resolvedFields.filter((f) => f.attributes.find((attr) => { var _a; return ((_a = attr.decl.ref) === null || _a === void 0 ? void 0 : _a.name) === '@unique'; }));
|
|
22
|
+
const modelLevelIds = (0, sdk_1.getModelIdFields)(dm);
|
|
23
|
+
const modelUniqueFields = (0, sdk_1.getModelUniqueFields)(dm);
|
|
24
|
+
if (idFields.length === 0 &&
|
|
25
|
+
modelLevelIds.length === 0 &&
|
|
26
|
+
uniqueFields.length === 0 &&
|
|
27
|
+
modelUniqueFields.length === 0) {
|
|
21
28
|
const { allows, denies, hasFieldValidation } = (0, sdk_1.analyzePolicies)(dm);
|
|
22
29
|
if (allows.length > 0 || denies.length > 0 || hasFieldValidation) {
|
|
23
30
|
// TODO: relax this requirement to require only @unique fields
|
|
24
31
|
// when access policies or field valdaition is used, require an @id field
|
|
25
|
-
accept('error', 'Model must include a field with @id attribute or a model-level @@id attribute', {
|
|
32
|
+
accept('error', 'Model must include a field with @id or @unique attribute, or a model-level @@id or @@unique attribute to use access policies', {
|
|
26
33
|
node: dm,
|
|
27
34
|
});
|
|
28
35
|
}
|
|
@@ -49,16 +56,22 @@ class DataModelValidator {
|
|
|
49
56
|
});
|
|
50
57
|
}
|
|
51
58
|
dm.fields.forEach((field) => this.validateField(field, accept));
|
|
59
|
+
if (!dm.isAbstract) {
|
|
60
|
+
dm.$resolvedFields
|
|
61
|
+
.filter((x) => { var _a; return (0, ast_1.isDataModel)((_a = x.type.reference) === null || _a === void 0 ? void 0 : _a.ref); })
|
|
62
|
+
.forEach((y) => {
|
|
63
|
+
this.validateRelationField(y, accept);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
52
66
|
}
|
|
53
67
|
validateField(field, accept) {
|
|
54
|
-
var _a;
|
|
55
68
|
if (field.type.array && field.type.optional) {
|
|
56
69
|
accept('error', 'Optional lists are not supported. Use either `Type[]` or `Type?`', { node: field.type });
|
|
57
70
|
}
|
|
58
|
-
field.
|
|
59
|
-
|
|
60
|
-
this.validateRelationField(field, accept);
|
|
71
|
+
if (field.type.unsupported && typeof field.type.unsupported.value.value !== 'string') {
|
|
72
|
+
accept('error', 'Unsupported type argument must be a string literal', { node: field.type.unsupported });
|
|
61
73
|
}
|
|
74
|
+
field.attributes.forEach((attr) => (0, utils_2.validateAttributeApplication)(attr, accept));
|
|
62
75
|
}
|
|
63
76
|
validateAttributes(dm, accept) {
|
|
64
77
|
dm.attributes.forEach((attr) => {
|
|
@@ -148,7 +161,7 @@ class DataModelValidator {
|
|
|
148
161
|
return { attr: relAttr, name, fields, references, valid };
|
|
149
162
|
}
|
|
150
163
|
isSelfRelation(field, relationName) {
|
|
151
|
-
var _a, _b, _c
|
|
164
|
+
var _a, _b, _c;
|
|
152
165
|
if (((_a = field.type.reference) === null || _a === void 0 ? void 0 : _a.ref) === field.$container) {
|
|
153
166
|
// field directly references back to its type
|
|
154
167
|
return true;
|
|
@@ -156,15 +169,16 @@ class DataModelValidator {
|
|
|
156
169
|
if (relationName) {
|
|
157
170
|
// field's relation points to another type, and that type's opposite relation field
|
|
158
171
|
// points back
|
|
159
|
-
const
|
|
160
|
-
if (
|
|
172
|
+
const oppositeModel = (_b = field.type.reference) === null || _b === void 0 ? void 0 : _b.ref;
|
|
173
|
+
if (oppositeModel) {
|
|
174
|
+
const oppositeModelFields = oppositeModel.$resolvedFields;
|
|
161
175
|
for (const oppositeField of oppositeModelFields) {
|
|
162
176
|
// find the opposite relation with the matching name
|
|
163
177
|
const relAttr = oppositeField.attributes.find((a) => { var _a; return ((_a = a.decl.ref) === null || _a === void 0 ? void 0 : _a.name) === '@relation'; });
|
|
164
178
|
if (relAttr) {
|
|
165
179
|
const relNameExpr = relAttr.args.find((a) => !a.name || a.name === 'name');
|
|
166
180
|
const relName = (0, sdk_1.getLiteral)(relNameExpr === null || relNameExpr === void 0 ? void 0 : relNameExpr.value);
|
|
167
|
-
if (relName === relationName && ((
|
|
181
|
+
if (relName === relationName && ((_c = oppositeField.type.reference) === null || _c === void 0 ? void 0 : _c.ref) === field.$container) {
|
|
168
182
|
// found an opposite relation field that points back to this field's type
|
|
169
183
|
return true;
|
|
170
184
|
}
|
|
@@ -175,24 +189,49 @@ class DataModelValidator {
|
|
|
175
189
|
return false;
|
|
176
190
|
}
|
|
177
191
|
validateRelationField(field, accept) {
|
|
178
|
-
var _a, _b, _c, _d, _e;
|
|
192
|
+
var _a, _b, _c, _d, _e, _f;
|
|
179
193
|
const thisRelation = this.parseRelation(field, accept);
|
|
180
194
|
if (!thisRelation.valid) {
|
|
181
195
|
return;
|
|
182
196
|
}
|
|
183
197
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
184
198
|
const oppositeModel = field.type.reference.ref;
|
|
185
|
-
|
|
199
|
+
// Use name because the current document might be updated
|
|
200
|
+
let oppositeFields = oppositeModel.$resolvedFields.filter((f) => { var _a, _b; return ((_b = (_a = f.type.reference) === null || _a === void 0 ? void 0 : _a.ref) === null || _b === void 0 ? void 0 : _b.name) === field.$container.name; });
|
|
186
201
|
oppositeFields = oppositeFields.filter((f) => {
|
|
187
202
|
const fieldRel = this.parseRelation(f);
|
|
188
203
|
return fieldRel.valid && fieldRel.name === thisRelation.name;
|
|
189
204
|
});
|
|
190
205
|
if (oppositeFields.length === 0) {
|
|
191
|
-
|
|
206
|
+
const node = field.$isInherited ? field.$container : field;
|
|
207
|
+
const info = { node, code: constants_1.IssueCodes.MissingOppositeRelation };
|
|
208
|
+
let relationFieldDocUri;
|
|
209
|
+
let relationDataModelName;
|
|
210
|
+
if (field.$isInherited) {
|
|
211
|
+
info.property = 'name';
|
|
212
|
+
const container = field.$container;
|
|
213
|
+
const abstractContainer = (_a = container.superTypes.find((x) => { var _a; return (_a = x.ref) === null || _a === void 0 ? void 0 : _a.fields.find((f) => f.name === field.name); })) === null || _a === void 0 ? void 0 : _a.ref;
|
|
214
|
+
relationFieldDocUri = (0, langium_1.getDocument)(abstractContainer).textDocument.uri;
|
|
215
|
+
relationDataModelName = abstractContainer.name;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
relationFieldDocUri = (0, langium_1.getDocument)(field).textDocument.uri;
|
|
219
|
+
relationDataModelName = field.$container.name;
|
|
220
|
+
}
|
|
221
|
+
const data = {
|
|
222
|
+
relationFieldName: field.name,
|
|
223
|
+
relationDataModelName,
|
|
224
|
+
relationFieldDocUri,
|
|
225
|
+
dataModelName: field.$container.name,
|
|
226
|
+
};
|
|
227
|
+
info.data = data;
|
|
228
|
+
accept('error', `The relation field "${field.name}" on model "${field.$container.name}" is missing an opposite relation field on model "${oppositeModel.name}"`, info);
|
|
192
229
|
return;
|
|
193
230
|
}
|
|
194
231
|
else if (oppositeFields.length > 1) {
|
|
195
|
-
oppositeFields
|
|
232
|
+
oppositeFields
|
|
233
|
+
.filter((x) => !x.$isInherited)
|
|
234
|
+
.forEach((f) => {
|
|
196
235
|
if (this.isSelfRelation(f)) {
|
|
197
236
|
// self relations are partial
|
|
198
237
|
// https://www.prisma.io/docs/concepts/components/prisma-schema/relations/self-relations
|
|
@@ -206,7 +245,7 @@ class DataModelValidator {
|
|
|
206
245
|
const oppositeField = oppositeFields[0];
|
|
207
246
|
const oppositeRelation = this.parseRelation(oppositeField);
|
|
208
247
|
let relationOwner;
|
|
209
|
-
if (((
|
|
248
|
+
if (((_b = thisRelation === null || thisRelation === void 0 ? void 0 : thisRelation.references) === null || _b === void 0 ? void 0 : _b.length) && ((_c = thisRelation.fields) === null || _c === void 0 ? void 0 : _c.length)) {
|
|
210
249
|
if ((oppositeRelation === null || oppositeRelation === void 0 ? void 0 : oppositeRelation.references) || (oppositeRelation === null || oppositeRelation === void 0 ? void 0 : oppositeRelation.fields)) {
|
|
211
250
|
accept('error', '"fields" and "references" must be provided only on one side of relation field', {
|
|
212
251
|
node: oppositeField,
|
|
@@ -217,7 +256,7 @@ class DataModelValidator {
|
|
|
217
256
|
relationOwner = oppositeField;
|
|
218
257
|
}
|
|
219
258
|
}
|
|
220
|
-
else if (((
|
|
259
|
+
else if (((_d = oppositeRelation === null || oppositeRelation === void 0 ? void 0 : oppositeRelation.references) === null || _d === void 0 ? void 0 : _d.length) && ((_e = oppositeRelation.fields) === null || _e === void 0 ? void 0 : _e.length)) {
|
|
221
260
|
if ((thisRelation === null || thisRelation === void 0 ? void 0 : thisRelation.references) || (thisRelation === null || thisRelation === void 0 ? void 0 : thisRelation.fields)) {
|
|
222
261
|
accept('error', '"fields" and "references" must be provided only on one side of relation field', {
|
|
223
262
|
node: field,
|
|
@@ -261,10 +300,10 @@ class DataModelValidator {
|
|
|
261
300
|
// UserData.userId field needs to be @unique
|
|
262
301
|
const containingModel = field.$container;
|
|
263
302
|
const uniqueFieldList = (0, utils_1.getUniqueFields)(containingModel);
|
|
264
|
-
(
|
|
303
|
+
(_f = thisRelation.fields) === null || _f === void 0 ? void 0 : _f.forEach((ref) => {
|
|
265
304
|
const refField = ref.target.ref;
|
|
266
305
|
if (refField) {
|
|
267
|
-
if (refField.attributes.find((a) => { var _a; return ((_a = a.decl.ref) === null || _a === void 0 ? void 0 : _a.name) === '@unique'; })) {
|
|
306
|
+
if (refField.attributes.find((a) => { var _a, _b; return ((_a = a.decl.ref) === null || _a === void 0 ? void 0 : _a.name) === '@id' || ((_b = a.decl.ref) === null || _b === void 0 ? void 0 : _b.name) === '@unique'; })) {
|
|
268
307
|
return;
|
|
269
308
|
}
|
|
270
309
|
if (uniqueFieldList.some((list) => list.includes(refField))) {
|
|
@@ -275,6 +314,17 @@ class DataModelValidator {
|
|
|
275
314
|
});
|
|
276
315
|
}
|
|
277
316
|
}
|
|
317
|
+
validateBaseAbstractModel(model, accept) {
|
|
318
|
+
model.superTypes.forEach((superType, index) => {
|
|
319
|
+
var _a;
|
|
320
|
+
if (!((_a = superType.ref) === null || _a === void 0 ? void 0 : _a.isAbstract))
|
|
321
|
+
accept('error', `Model ${superType.$refText} cannot be extended because it's not abstract`, {
|
|
322
|
+
node: model,
|
|
323
|
+
property: 'superTypes',
|
|
324
|
+
index,
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
}
|
|
278
328
|
}
|
|
279
329
|
exports.default = DataModelValidator;
|
|
280
330
|
//# sourceMappingURL=datamodel-validator.js.map
|