@simtlix/simfinity-js 1.5.0 → 1.7.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 +1371 -8
- package/eslint.config.mjs +29 -21
- package/package.json +6 -23
- package/src/const/QLOperator.js +2 -4
- package/src/const/QLSort.js +3 -5
- package/src/const/QLValue.js +2 -4
- package/src/errors/internal-server.error.js +2 -2
- package/src/errors/simfinity.error.js +1 -1
- package/src/index.js +54 -41
- package/tests/prevent-collection-creation.test.js +7 -6
- package/tests/validated-scalar.test.js +7 -4
package/eslint.config.mjs
CHANGED
|
@@ -16,48 +16,56 @@ export default [
|
|
|
16
16
|
{
|
|
17
17
|
ignores: ["node_modules/*", "data/*", "eslint.config.mjs"],
|
|
18
18
|
},
|
|
19
|
-
|
|
19
|
+
js.configs.recommended,
|
|
20
20
|
{
|
|
21
21
|
files: ["**/*.js"],
|
|
22
22
|
languageOptions: {
|
|
23
23
|
globals: {
|
|
24
|
-
...globals.commonjs,
|
|
25
24
|
...globals.node,
|
|
26
|
-
...globals.
|
|
25
|
+
...globals.es2024,
|
|
27
26
|
},
|
|
28
|
-
|
|
29
27
|
ecmaVersion: 2024,
|
|
30
|
-
sourceType: "
|
|
28
|
+
sourceType: "module",
|
|
31
29
|
},
|
|
32
|
-
|
|
33
30
|
rules: {
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
31
|
+
// Code style and best practices (relaxed to match existing code)
|
|
32
|
+
"quotes": ["error", "single"],
|
|
33
|
+
"semi": ["error", "always"],
|
|
34
|
+
"comma-dangle": ["error", "always-multiline"],
|
|
35
|
+
"object-curly-spacing": ["error", "always"],
|
|
36
|
+
"array-bracket-spacing": ["error", "never"],
|
|
37
|
+
|
|
38
|
+
// ES6+ features
|
|
39
|
+
"prefer-const": "error",
|
|
40
|
+
"no-var": "error",
|
|
41
|
+
"prefer-arrow-callback": "off", // Allow function declarations
|
|
42
|
+
"arrow-spacing": "error",
|
|
43
|
+
|
|
44
|
+
// Best practices
|
|
45
|
+
"no-console": "off", // Allow console for this project
|
|
46
|
+
"no-underscore-dangle": "off", // Allow underscore dangle for MongoDB _id
|
|
38
47
|
"no-await-in-loop": "off",
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
"max-len": "off", // Disable max-len for now
|
|
49
|
+
"indent": "off", // Disable indent for now to match existing style
|
|
50
|
+
|
|
51
|
+
// Parameter reassignment (common in GraphQL resolvers)
|
|
52
|
+
"no-param-reassign": ["error", { "props": false }],
|
|
53
|
+
|
|
54
|
+
// Function formatting
|
|
44
55
|
"function-paren-newline": "off",
|
|
45
56
|
"function-call-argument-newline": "off",
|
|
46
|
-
|
|
57
|
+
|
|
58
|
+
// Restricted syntax
|
|
47
59
|
"no-restricted-syntax": ["error", {
|
|
48
60
|
selector: "ForInStatement",
|
|
49
61
|
message: "for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.",
|
|
50
62
|
}, {
|
|
51
|
-
selector: "LabeledStatement",
|
|
63
|
+
selector: "LabeledStatement",
|
|
52
64
|
message: "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.",
|
|
53
65
|
}, {
|
|
54
66
|
selector: "WithStatement",
|
|
55
67
|
message: "`with` is disallowed in strict mode because it makes code impossible to predict and optimize.",
|
|
56
68
|
}],
|
|
57
|
-
|
|
58
|
-
"import/no-unresolved": ["error", {
|
|
59
|
-
ignore: ["graphql", "mongoose"],
|
|
60
|
-
}],
|
|
61
69
|
},
|
|
62
70
|
},
|
|
63
71
|
];
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simtlix/simfinity-js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
6
7
|
"scripts": {
|
|
7
|
-
"test": "
|
|
8
|
-
"test:watch": "
|
|
9
|
-
"test:coverage": "
|
|
8
|
+
"test": "vitest run",
|
|
9
|
+
"test:watch": "vitest",
|
|
10
|
+
"test:coverage": "vitest --coverage",
|
|
10
11
|
"lint": "eslint '**/*.js'",
|
|
11
12
|
"lint-fix": "eslint --fix '**/*.js'"
|
|
12
13
|
},
|
|
@@ -24,34 +25,16 @@
|
|
|
24
25
|
"mongoose": "^8.16.2"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
|
-
"@eslint/compat": "^1.2.0",
|
|
28
|
-
"@eslint/eslintrc": "^3.1.0",
|
|
29
28
|
"@eslint/js": "^9.30.1",
|
|
30
29
|
"eslint": "^9.30.1",
|
|
31
|
-
"eslint-config-airbnb-base": "^15.0.0",
|
|
32
|
-
"eslint-plugin-import": "^2.32.0",
|
|
33
|
-
"ghooks": "^2.0.4",
|
|
34
30
|
"globals": "^16.3.0",
|
|
35
|
-
"
|
|
31
|
+
"vitest": "^3.2.4"
|
|
36
32
|
},
|
|
37
33
|
"config": {
|
|
38
|
-
"ghooks": {
|
|
39
|
-
"pre-commit": "npm run lint || npm run lint-fix"
|
|
40
|
-
},
|
|
41
34
|
"owner": "simtlix"
|
|
42
35
|
},
|
|
43
36
|
"optionalDependencies": {
|
|
44
37
|
"graphql": "^16.11.0",
|
|
45
38
|
"mongoose": "^8.16.2"
|
|
46
|
-
},
|
|
47
|
-
"jest": {
|
|
48
|
-
"testEnvironment": "node",
|
|
49
|
-
"testMatch": [
|
|
50
|
-
"**/tests/**/*.test.js"
|
|
51
|
-
],
|
|
52
|
-
"collectCoverageFrom": [
|
|
53
|
-
"src/**/*.js",
|
|
54
|
-
"!src/index.js"
|
|
55
|
-
]
|
|
56
39
|
}
|
|
57
40
|
}
|
package/src/const/QLOperator.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { GraphQLEnumType } = graphql;
|
|
1
|
+
import { GraphQLEnumType } from 'graphql';
|
|
4
2
|
|
|
5
3
|
const QLOperator = new GraphQLEnumType({
|
|
6
4
|
name: 'QLOperator',
|
|
@@ -38,4 +36,4 @@ const QLOperator = new GraphQLEnumType({
|
|
|
38
36
|
},
|
|
39
37
|
});
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
export default QLOperator;
|
package/src/const/QLSort.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const {
|
|
1
|
+
import {
|
|
4
2
|
GraphQLInputObjectType,
|
|
5
3
|
GraphQLNonNull,
|
|
6
4
|
GraphQLEnumType,
|
|
7
5
|
GraphQLString,
|
|
8
|
-
}
|
|
6
|
+
} from 'graphql';
|
|
9
7
|
|
|
10
8
|
const QLSortOrder = new GraphQLEnumType({
|
|
11
9
|
name: 'QLSortOrder',
|
|
@@ -27,4 +25,4 @@ const QLSort = new GraphQLInputObjectType({
|
|
|
27
25
|
}),
|
|
28
26
|
});
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
export default QLSort;
|
package/src/const/QLValue.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { GraphQLScalarType, Kind } = graphql;
|
|
1
|
+
import { GraphQLScalarType, Kind } from 'graphql';
|
|
4
2
|
|
|
5
3
|
function parseQLValue(value) {
|
|
6
4
|
return value;
|
|
@@ -38,4 +36,4 @@ const QLValue = new GraphQLScalarType({
|
|
|
38
36
|
},
|
|
39
37
|
});
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
export default QLValue;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import SimfinityError from './simfinity.error.js';
|
|
2
2
|
|
|
3
3
|
class InternalServerError extends SimfinityError {
|
|
4
4
|
constructor(message, cause) {
|
|
@@ -8,4 +8,4 @@ class InternalServerError extends SimfinityError {
|
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
export default InternalServerError;
|
package/src/index.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
const mongoose = require('mongoose');
|
|
3
|
-
|
|
4
|
-
const SimfinityError = require('./errors/simfinity.error');
|
|
5
|
-
const InternalServerError = require('./errors/internal-server.error');
|
|
6
|
-
const QLOperator = require('./const/QLOperator');
|
|
7
|
-
const QLValue = require('./const/QLValue');
|
|
8
|
-
const QLSort = require('./const/QLSort');
|
|
9
|
-
|
|
10
|
-
mongoose.set('strictQuery', false);
|
|
11
|
-
|
|
12
|
-
const {
|
|
1
|
+
import {
|
|
13
2
|
GraphQLObjectType, GraphQLString, GraphQLID, GraphQLSchema, GraphQLList,
|
|
14
3
|
GraphQLNonNull, GraphQLInputObjectType, GraphQLScalarType, __Field,
|
|
15
4
|
GraphQLInt, GraphQLEnumType, GraphQLBoolean, GraphQLFloat, Kind,
|
|
16
|
-
}
|
|
5
|
+
} from 'graphql';
|
|
6
|
+
import mongoose from 'mongoose';
|
|
7
|
+
|
|
8
|
+
import SimfinityError from './errors/simfinity.error.js';
|
|
9
|
+
import InternalServerError from './errors/internal-server.error.js';
|
|
10
|
+
import QLOperator from './const/QLOperator.js';
|
|
11
|
+
import QLValue from './const/QLValue.js';
|
|
12
|
+
import QLSort from './const/QLSort.js';
|
|
13
|
+
|
|
14
|
+
mongoose.set('strictQuery', false);
|
|
17
15
|
|
|
18
16
|
// Adding 'extensions' field into instronspection query
|
|
19
17
|
const RelationType = new GraphQLObjectType({
|
|
@@ -83,19 +81,19 @@ const buildErrorFormatter = (callback) => {
|
|
|
83
81
|
|
|
84
82
|
const middlewares = [];
|
|
85
83
|
|
|
86
|
-
|
|
84
|
+
export const use = (middleware) => {
|
|
87
85
|
middlewares.push(middleware);
|
|
88
86
|
};
|
|
89
87
|
|
|
90
|
-
|
|
88
|
+
export { buildErrorFormatter };
|
|
91
89
|
|
|
92
|
-
|
|
90
|
+
export { SimfinityError };
|
|
93
91
|
|
|
94
|
-
|
|
92
|
+
export { InternalServerError };
|
|
95
93
|
|
|
96
94
|
let preventCollectionCreation = false;
|
|
97
95
|
|
|
98
|
-
|
|
96
|
+
export const preventCreatingCollection = (prevent) => {
|
|
99
97
|
preventCollectionCreation = !!prevent;
|
|
100
98
|
};
|
|
101
99
|
|
|
@@ -416,7 +414,7 @@ const buildInputType = (gqltype) => {
|
|
|
416
414
|
|
|
417
415
|
const getInputType = (type) => typesDict.types[type.name].inputType;
|
|
418
416
|
|
|
419
|
-
|
|
417
|
+
export { getInputType };
|
|
420
418
|
|
|
421
419
|
const buildPendingInputTypes = (waitingForInputType) => {
|
|
422
420
|
const stillWaitingInputType = {};
|
|
@@ -549,17 +547,17 @@ const iterateonCollectionFields = async (materializedModel, gqltype, objectId, s
|
|
|
549
547
|
for (const [collectionFieldKey, collectionField] of
|
|
550
548
|
Object.entries(materializedModel.collectionFields)) {
|
|
551
549
|
if (collectionField.added) {
|
|
552
|
-
|
|
550
|
+
|
|
553
551
|
await executeItemFunction(gqltype, collectionFieldKey, objectId, session,
|
|
554
552
|
collectionField.added, operations.SAVE);
|
|
555
553
|
}
|
|
556
554
|
if (collectionField.updated) {
|
|
557
|
-
|
|
555
|
+
|
|
558
556
|
await executeItemFunction(gqltype, collectionFieldKey, objectId, session,
|
|
559
557
|
collectionField.updated, operations.UPDATE);
|
|
560
558
|
}
|
|
561
559
|
if (collectionField.deleted) {
|
|
562
|
-
|
|
560
|
+
|
|
563
561
|
await executeItemFunction(gqltype, collectionFieldKey, objectId, session,
|
|
564
562
|
collectionField.deleted, operations.DELETE);
|
|
565
563
|
}
|
|
@@ -681,7 +679,7 @@ const onSaveObject = async (Model, gqltype, controller, args, session, linkToPar
|
|
|
681
679
|
return result;
|
|
682
680
|
};
|
|
683
681
|
|
|
684
|
-
|
|
682
|
+
export const saveObject = async (typeName, args, session) => {
|
|
685
683
|
const type = typesDict.types[typeName];
|
|
686
684
|
return onSaveObject(type.model, type.gqltype, type.controller, args, session);
|
|
687
685
|
};
|
|
@@ -1389,9 +1387,9 @@ const buildQuery = async (input, gqltype, isCount) => {
|
|
|
1389
1387
|
|
|
1390
1388
|
if (sort.field.indexOf('.') >= 0) {
|
|
1391
1389
|
const sortParts = sort.field.split('.');
|
|
1392
|
-
|
|
1390
|
+
|
|
1393
1391
|
fixedSortField = sortParts[0];
|
|
1394
|
-
|
|
1392
|
+
|
|
1395
1393
|
for (let i = 1; i < sortParts.length - 1; i++) {
|
|
1396
1394
|
fixedSortField += `_${sortParts[i]}`;
|
|
1397
1395
|
}
|
|
@@ -1536,15 +1534,36 @@ const buildRootQuery = (name, includedTypes) => {
|
|
|
1536
1534
|
|
|
1537
1535
|
/* Creating a new GraphQL Schema, with options query which defines query
|
|
1538
1536
|
we will allow users to use when they are making request. */
|
|
1539
|
-
|
|
1540
|
-
includedMutationTypes, includedCustomMutations) =>
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1537
|
+
export const createSchema = (includedQueryTypes,
|
|
1538
|
+
includedMutationTypes, includedCustomMutations) => {
|
|
1539
|
+
|
|
1540
|
+
// Auto-generate resolvers for all registered types now that all types are available
|
|
1541
|
+
Object.values(typesDict.types).forEach(typeInfo => {
|
|
1542
|
+
if (typeInfo.gqltype) {
|
|
1543
|
+
autoGenerateResolvers(typeInfo.gqltype);
|
|
1544
|
+
}
|
|
1545
|
+
});
|
|
1544
1546
|
|
|
1545
|
-
|
|
1547
|
+
return new GraphQLSchema({
|
|
1548
|
+
query: buildRootQuery('RootQueryType', includedQueryTypes),
|
|
1549
|
+
mutation: buildMutation('Mutation', includedMutationTypes, includedCustomMutations),
|
|
1550
|
+
});
|
|
1551
|
+
};
|
|
1552
|
+
|
|
1553
|
+
export const getModel = (gqltype) => typesDict.types[gqltype.name].model;
|
|
1554
|
+
|
|
1555
|
+
export const getType = (typeName) => {
|
|
1556
|
+
if (typeof typeName === 'string') {
|
|
1557
|
+
return typesDict.types[typeName]?.gqltype;
|
|
1558
|
+
}
|
|
1559
|
+
// If it's already a GraphQL type object, get by its name
|
|
1560
|
+
if (typeName && typeName.name) {
|
|
1561
|
+
return typesDict.types[typeName.name]?.gqltype;
|
|
1562
|
+
}
|
|
1563
|
+
return null;
|
|
1564
|
+
};
|
|
1546
1565
|
|
|
1547
|
-
|
|
1566
|
+
export const registerMutation = (name, description, inputModel, outputModel, callback) => {
|
|
1548
1567
|
registeredMutations[name] = {
|
|
1549
1568
|
description,
|
|
1550
1569
|
inputModel,
|
|
@@ -1602,7 +1621,7 @@ const autoGenerateResolvers = (gqltype) => {
|
|
|
1602
1621
|
}
|
|
1603
1622
|
};
|
|
1604
1623
|
|
|
1605
|
-
|
|
1624
|
+
export const connect = (model, gqltype, simpleEntityEndpointName,
|
|
1606
1625
|
listEntitiesEndpointName, controller, onModelCreated, stateMachine) => {
|
|
1607
1626
|
waitingInputType[gqltype.name] = {
|
|
1608
1627
|
model,
|
|
@@ -1619,12 +1638,9 @@ module.exports.connect = (model, gqltype, simpleEntityEndpointName,
|
|
|
1619
1638
|
};
|
|
1620
1639
|
|
|
1621
1640
|
typesDictForUpdate.types[gqltype.name] = { ...typesDict.types[gqltype.name] };
|
|
1622
|
-
|
|
1623
|
-
// Auto-generate resolve methods for relationship fields if not already defined
|
|
1624
|
-
autoGenerateResolvers(gqltype);
|
|
1625
1641
|
};
|
|
1626
1642
|
|
|
1627
|
-
|
|
1643
|
+
export const addNoEndpointType = (gqltype) => {
|
|
1628
1644
|
waitingInputType[gqltype.name] = {
|
|
1629
1645
|
gqltype,
|
|
1630
1646
|
};
|
|
@@ -1650,9 +1666,6 @@ module.exports.addNoEndpointType = (gqltype) => {
|
|
|
1650
1666
|
};
|
|
1651
1667
|
|
|
1652
1668
|
typesDictForUpdate.types[gqltype.name] = { ...typesDict.types[gqltype.name] };
|
|
1653
|
-
|
|
1654
|
-
// Auto-generate resolve methods for relationship fields if not already defined
|
|
1655
|
-
autoGenerateResolvers(gqltype);
|
|
1656
1669
|
};
|
|
1657
1670
|
|
|
1658
|
-
|
|
1671
|
+
export { createValidatedScalar };
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
describe, test, expect, beforeEach, afterEach, vi,
|
|
3
|
+
} from 'vitest';
|
|
4
|
+
import mongoose from 'mongoose';
|
|
5
|
+
import { GraphQLObjectType, GraphQLString, GraphQLID } from 'graphql';
|
|
6
|
+
import * as simfinity from '../src/index.js';
|
|
4
7
|
|
|
5
8
|
describe('preventCreatingCollection option', () => {
|
|
6
9
|
let createCollectionSpy;
|
|
7
10
|
|
|
8
11
|
beforeEach(() => {
|
|
9
|
-
// Reset modules to have a clean state for each test
|
|
10
|
-
jest.resetModules();
|
|
11
12
|
// Spy on the createCollection method of the mongoose model prototype
|
|
12
|
-
createCollectionSpy =
|
|
13
|
+
createCollectionSpy = vi.spyOn(mongoose.Model, 'createCollection').mockImplementation(() => Promise.resolve());
|
|
13
14
|
});
|
|
14
15
|
|
|
15
16
|
afterEach(() => {
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import {
|
|
2
|
+
describe, test, expect, beforeAll,
|
|
3
|
+
} from 'vitest';
|
|
4
|
+
import {
|
|
2
5
|
GraphQLObjectType, GraphQLString, GraphQLInt, GraphQLID, GraphQLList, GraphQLNonNull,
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
} from 'graphql';
|
|
7
|
+
import { createValidatedScalar } from '../src/index.js';
|
|
8
|
+
import * as simfinity from '../src/index.js';
|
|
6
9
|
|
|
7
10
|
describe('Custom Validated Scalar Types', () => {
|
|
8
11
|
let EmailScalar;
|