@simtlix/simfinity-js 2.4.2 → 2.4.6

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/git-report.js ADDED
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execFileSync } from 'node:child_process';
4
+ import { writeFileSync } from 'node:fs';
5
+ import { resolve } from 'node:path';
6
+
7
+ const CHANGE_TYPE_LABELS = {
8
+ A: 'Added',
9
+ M: 'Modified',
10
+ D: 'Deleted',
11
+ R: 'Renamed',
12
+ C: 'Copied',
13
+ T: 'TypeChanged',
14
+ };
15
+
16
+ const COMMIT_DELIMITER = '---GIT_REPORT_COMMIT---';
17
+ const FIELD_DELIMITER = '---GIT_REPORT_FIELD---';
18
+
19
+ function printHelp() {
20
+ const help = `
21
+ Usage: node git-report.js --branch <branch> --author <author> --months <N> [--output <file.csv>]
22
+
23
+ Generate a CSV report of git commits for a given author on a branch within a time period.
24
+
25
+ Required arguments:
26
+ --branch <branch> Git branch name to analyze
27
+ --author <author> Git author name or email to filter by
28
+ --months <N> Number of months to look back from today
29
+
30
+ Optional arguments:
31
+ --output <file> Output CSV file path (default: git-report.csv)
32
+ --help, -h Show this help message and exit
33
+
34
+ Output:
35
+ A CSV file with one row per affected file per commit, containing:
36
+ commit_hash, author, date, message, change_type, file_path
37
+
38
+ Examples:
39
+ node git-report.js --branch master --author "John Doe" --months 3
40
+ node git-report.js --branch main --author john@example.com --months 6 --output report.csv
41
+ `;
42
+ console.log(help.trim());
43
+ }
44
+
45
+ function parseArgs(argv) {
46
+ const args = argv.slice(2);
47
+
48
+ if (args.includes('--help') || args.includes('-h')) {
49
+ printHelp();
50
+ process.exit(0);
51
+ }
52
+
53
+ const opts = {};
54
+ for (let i = 0; i < args.length; i++) {
55
+ switch (args[i]) {
56
+ case '--branch':
57
+ opts.branch = args[++i];
58
+ break;
59
+ case '--author':
60
+ opts.author = args[++i];
61
+ break;
62
+ case '--months':
63
+ opts.months = args[++i];
64
+ break;
65
+ case '--output':
66
+ opts.output = args[++i];
67
+ break;
68
+ default:
69
+ console.error(`Unknown argument: ${args[i]}`);
70
+ printHelp();
71
+ process.exit(1);
72
+ }
73
+ }
74
+
75
+ const missing = [];
76
+ if (!opts.branch) missing.push('--branch');
77
+ if (!opts.author) missing.push('--author');
78
+ if (!opts.months) missing.push('--months');
79
+
80
+ if (missing.length > 0) {
81
+ console.error(`Missing required arguments: ${missing.join(', ')}`);
82
+ printHelp();
83
+ process.exit(1);
84
+ }
85
+
86
+ const months = parseInt(opts.months, 10);
87
+ if (Number.isNaN(months) || months <= 0) {
88
+ console.error('--months must be a positive integer');
89
+ process.exit(1);
90
+ }
91
+ opts.months = months;
92
+ opts.output = opts.output || 'git-report.csv';
93
+
94
+ return opts;
95
+ }
96
+
97
+ function validateGitEnvironment() {
98
+ try {
99
+ execFileSync('git', ['--version'], { stdio: 'pipe' });
100
+ } catch {
101
+ console.error('Error: git is not installed or not found in PATH.');
102
+ process.exit(1);
103
+ }
104
+
105
+ try {
106
+ execFileSync('git', ['rev-parse', '--is-inside-work-tree'], { stdio: 'pipe' });
107
+ } catch {
108
+ console.error('Error: current directory is not inside a git repository.');
109
+ process.exit(1);
110
+ }
111
+ }
112
+
113
+ function computeSinceDate(months) {
114
+ const date = new Date();
115
+ date.setMonth(date.getMonth() - months);
116
+ return date.toISOString().slice(0, 10);
117
+ }
118
+
119
+ function escapeCsvField(value) {
120
+ const str = String(value).replace(/\r?\n/g, ' ');
121
+ if (str.includes(',') || str.includes('"') || str.includes('\n')) {
122
+ return `"${str.replace(/"/g, '""')}"`;
123
+ }
124
+ return str;
125
+ }
126
+
127
+ function getGitLog(branch, author, sinceDate) {
128
+ const format = [
129
+ `${COMMIT_DELIMITER}`,
130
+ `%h${FIELD_DELIMITER}%an${FIELD_DELIMITER}%ai${FIELD_DELIMITER}%s`,
131
+ ].join('');
132
+
133
+ const args = [
134
+ 'log',
135
+ `--format=${format}`,
136
+ '--name-status',
137
+ `--author=${author}`,
138
+ `--since=${sinceDate}`,
139
+ branch,
140
+ ];
141
+
142
+ try {
143
+ return execFileSync('git', args, { encoding: 'utf-8', maxBuffer: 50 * 1024 * 1024 });
144
+ } catch (err) {
145
+ console.error(`Error running git log: ${err.message}`);
146
+ process.exit(1);
147
+ }
148
+ }
149
+
150
+ function parseGitLog(rawOutput) {
151
+ const rows = [];
152
+ const commits = rawOutput.split(COMMIT_DELIMITER).filter((s) => s.trim());
153
+
154
+ for (const block of commits) {
155
+ const lines = block.trim().split('\n');
156
+ if (lines.length === 0) continue;
157
+
158
+ const headerLine = lines[0];
159
+ const parts = headerLine.split(FIELD_DELIMITER);
160
+ if (parts.length < 4) continue;
161
+
162
+ const [hash, author, dateRaw, message] = parts;
163
+ const date = dateRaw.slice(0, 10);
164
+
165
+ for (let i = 1; i < lines.length; i++) {
166
+ const line = lines[i].trim();
167
+ if (!line) continue;
168
+
169
+ const match = line.match(/^([AMDRTC])\d*\t(.+)$/);
170
+ if (!match) continue;
171
+
172
+ const statusCode = match[1];
173
+ const filePath = match[2].includes('\t') ? match[2].split('\t').pop() : match[2];
174
+ const changeType = CHANGE_TYPE_LABELS[statusCode] || statusCode;
175
+
176
+ rows.push({
177
+ commit_hash: hash,
178
+ author,
179
+ date,
180
+ message,
181
+ change_type: changeType,
182
+ file_path: filePath,
183
+ });
184
+ }
185
+ }
186
+
187
+ return rows;
188
+ }
189
+
190
+ function writeCsv(rows, outputPath) {
191
+ const columns = ['commit_hash', 'author', 'date', 'message', 'change_type', 'file_path'];
192
+ const header = columns.join(',');
193
+ const lines = rows.map((row) => columns.map((col) => escapeCsvField(row[col])).join(','));
194
+
195
+ const csv = [header, ...lines, ''].join('\n');
196
+ const absPath = resolve(outputPath);
197
+ writeFileSync(absPath, csv, 'utf-8');
198
+ return absPath;
199
+ }
200
+
201
+ function main() {
202
+ const opts = parseArgs(process.argv);
203
+ validateGitEnvironment();
204
+
205
+ const sinceDate = computeSinceDate(opts.months);
206
+ console.error(`Searching commits on branch "${opts.branch}" by "${opts.author}" since ${sinceDate}...`);
207
+
208
+ const rawLog = getGitLog(opts.branch, opts.author, sinceDate);
209
+ const rows = parseGitLog(rawLog);
210
+
211
+ const uniqueCommits = new Set(rows.map((r) => r.commit_hash)).size;
212
+
213
+ if (rows.length === 0) {
214
+ console.error('No commits found matching the criteria.');
215
+ process.exit(0);
216
+ }
217
+
218
+ const absPath = writeCsv(rows, opts.output);
219
+
220
+ console.error(`Done. ${uniqueCommits} commit(s), ${rows.length} file change(s).`);
221
+ console.error(`Report written to: ${absPath}`);
222
+ }
223
+
224
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simtlix/simfinity-js",
3
- "version": "2.4.2",
3
+ "version": "2.4.6",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/auth/index.js CHANGED
@@ -16,19 +16,19 @@
16
16
  *
17
17
  * const permissions = {
18
18
  * Query: {
19
- * users: requireAuth(),
20
- * adminDashboard: requireRole('ADMIN')
19
+ * series: requireAuth(),
20
+ * seasons: requireAuth(),
21
21
  * },
22
22
  * Mutation: {
23
- * publishPost: requireRole('EDITOR')
23
+ * deleteserie: requireRole('admin'),
24
+ * deletestar: requireRole('admin'),
24
25
  * },
25
- * User: {
26
+ * serie: {
26
27
  * '*': requireAuth(),
27
- * email: requireRole('ADMIN')
28
28
  * }
29
29
  * };
30
30
  *
31
- * const authPlugin = createAuthPlugin(permissions, { defaultPolicy: 'DENY' });
31
+ * const authPlugin = createAuthPlugin(permissions, { defaultPolicy: 'ALLOW' });
32
32
  * const yoga = createYoga({ schema, plugins: [authPlugin] });
33
33
  */
34
34
 
package/src/index.js CHANGED
@@ -416,8 +416,8 @@ const buildInputType = (gqltype) => {
416
416
  if (fieldEntry.type.ofType === gqltype) {
417
417
  selfReferenceCollections[fieldEntryName] = fieldEntry;
418
418
  } else {
419
- const listInputTypeForAdd = graphQLListInputType(typesDict, fieldEntry, fieldEntryName, 'A', fieldEntry.extensions?.relation?.connectionField);
420
- const listInputTypeForUpdate = graphQLListInputType(typesDictForUpdate, fieldEntry, fieldEntryName, 'U', fieldEntry.extensions?.relation?.connectionField);
419
+ const listInputTypeForAdd = graphQLListInputType(typesDict, fieldEntry, fieldEntryName, gqltype.name + 'A', fieldEntry.extensions?.relation?.connectionField);
420
+ const listInputTypeForUpdate = graphQLListInputType(typesDictForUpdate, fieldEntry, fieldEntryName, gqltype.name +'U', fieldEntry.extensions?.relation?.connectionField);
421
421
  if (listInputTypeForAdd && listInputTypeForUpdate) {
422
422
  fieldArg.type = listInputTypeForAdd;
423
423
  fieldArgForUpdate.type = listInputTypeForUpdate;
@@ -680,7 +680,10 @@ const onUpdateSubject = async (Model, gqltype, controller, args, session, linkTo
680
680
 
681
681
  if (args[fieldEntryName] === null
682
682
  && !(fieldEntry.type instanceof GraphQLNonNull)) {
683
- materializedModel.modelArgs = { ...materializedModel.modelArgs, $unset: { [fieldEntryName]: '' } };
683
+ materializedModel.modelArgs = {
684
+ ...materializedModel.modelArgs,
685
+ $unset: { ...materializedModel.modelArgs.$unset, [fieldEntryName]: '' },
686
+ };
684
687
  }
685
688
  });
686
689