bd-orm 0.0.1

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.
Files changed (59) hide show
  1. package/.github/workflows/build-and-test.yml +26 -0
  2. package/.github/workflows/publish.yml +36 -0
  3. package/.prettierrc.json +14 -0
  4. package/CHANGELOG.md +3 -0
  5. package/README.md +5 -0
  6. package/check NBR en TODO.txt +32 -0
  7. package/dist/_/BdORMBase.d.ts +111 -0
  8. package/dist/_/BdORMBase.js +262 -0
  9. package/dist/_/BdORMCrud.d.ts +51 -0
  10. package/dist/_/BdORMCrud.js +223 -0
  11. package/dist/_/BdORMError.d.ts +4 -0
  12. package/dist/_/BdORMError.js +14 -0
  13. package/dist/_/BdOrmConnection.d.ts +32 -0
  14. package/dist/_/BdOrmConnection.js +5 -0
  15. package/dist/_/cdsBaseOrm.d.ts +12 -0
  16. package/dist/_/cdsBaseOrm.js +21 -0
  17. package/dist/dbConnections/BdOrmDbConnectionCapHana/index.d.ts +26 -0
  18. package/dist/dbConnections/BdOrmDbConnectionCapHana/index.js +78 -0
  19. package/dist/dbConnections/BdOrmDbConnectionCapHana/utils.d.ts +14 -0
  20. package/dist/dbConnections/BdOrmDbConnectionCapHana/utils.js +49 -0
  21. package/dist/dbConnections/BdOrmDbConnectionCapSqlite/index.d.ts +22 -0
  22. package/dist/dbConnections/BdOrmDbConnectionCapSqlite/index.js +85 -0
  23. package/dist/dbConnections/BdOrmDbConnectionCapSqlite/utils.d.ts +3 -0
  24. package/dist/dbConnections/BdOrmDbConnectionCapSqlite/utils.js +74 -0
  25. package/dist/dbConnections/BdOrmDbConnectionSQLBase.d.ts +32 -0
  26. package/dist/dbConnections/BdOrmDbConnectionSQLBase.js +99 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.js +18 -0
  29. package/dist/test-assets/Post.d.ts +12 -0
  30. package/dist/test-assets/Post.js +13 -0
  31. package/dist/test-assets/User.d.ts +16 -0
  32. package/dist/test-assets/User.js +13 -0
  33. package/dist/test-assets/jestUtils.d.ts +5 -0
  34. package/dist/test-assets/jestUtils.js +30 -0
  35. package/jest.config.js +7 -0
  36. package/package.json +53 -0
  37. package/src/_/BdORMBase.ts +288 -0
  38. package/src/_/BdORMCrud.test.ts +198 -0
  39. package/src/_/BdORMCrud.ts +240 -0
  40. package/src/_/BdORMError.ts +10 -0
  41. package/src/_/BdORMbase.test.ts +166 -0
  42. package/src/_/BdOrmConnection.ts +39 -0
  43. package/src/_/cdsBaseOrm.ts +18 -0
  44. package/src/dbConnections/BdOrmDbConnectionCapHana/index.ts +95 -0
  45. package/src/dbConnections/BdOrmDbConnectionCapHana/utils.ts +47 -0
  46. package/src/dbConnections/BdOrmDbConnectionCapHana.test.ts +18 -0
  47. package/src/dbConnections/BdOrmDbConnectionCapSqlite/index.ts +89 -0
  48. package/src/dbConnections/BdOrmDbConnectionCapSqlite/utils.ts +75 -0
  49. package/src/dbConnections/BdOrmDbConnectionCapSqlite.test.ts +41 -0
  50. package/src/dbConnections/BdOrmDbConnectionSQLBase.ts +124 -0
  51. package/src/index.ts +8 -0
  52. package/src/test-assets/Post.ts +16 -0
  53. package/src/test-assets/User.ts +18 -0
  54. package/src/test-assets/db/BdOrm.cds +20 -0
  55. package/src/test-assets/db/csv/bdorm-user.csv +3 -0
  56. package/src/test-assets/db/views/user.hdbview +3 -0
  57. package/src/test-assets/jestUtils.ts +24 -0
  58. package/tsconfig.json +16 -0
  59. package/validate-package.js +113 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Use this connection class when writing unit tests
3
+ *
4
+ * This class extends the BdOrmDbConnection and provides methods to interact with a SQLite in-memory database
5
+ * for unit testing purposes. It includes functionality to create, read, update, delete, and list records
6
+ * in the database, as well as to execute arbitrary queries.
7
+ *
8
+ * The class maintains a record of deployed databases and primary keys for tables to optimize database
9
+ * operations. It uses the SAP CDS framework for database connectivity and operations.
10
+ *
11
+ * it automatically fills the database with data from the CSV files that are found in the provided database folder
12
+ * or from the CSV files provided in the constructor
13
+ */
14
+ import { BdORMError } from '../../_/BdORMError';
15
+ import BdOrmDbConnectionSQLBase from '../BdOrmDbConnectionSQLBase';
16
+ import { addCsvFilesFromDBFolder, deployHdbViewFiles, fillTableFromCsv } from './utils';
17
+ import cds from '@sap/cds';
18
+
19
+ type TableInfo = { pk: number; name: string; type: string };
20
+
21
+ const PRIMARY_KEYS: Record<string, string> = {};
22
+ const TABLE_INFO: Record<string, TableInfo[]> = {};
23
+
24
+ export default class BdOrmDbConnectionCapSqlite extends BdOrmDbConnectionSQLBase {
25
+ private readonly _csvFiles: string[] = [];
26
+ private _deployed: boolean = false;
27
+ private _dbPath: string = '';
28
+
29
+ protected async _db() {
30
+ let db;
31
+ if (!this._deployed) {
32
+ //@ts-ignore jest zegt cds.deploy does not exists
33
+ await cds.deploy(this._dbPath).to('sqlite::memory:');
34
+ db = await cds.connect.to('db');
35
+ if (!this._csvFiles.length) await addCsvFilesFromDBFolder(db, this._dbPath);
36
+ else {
37
+ for (const csvFile of this._csvFiles) {
38
+ await fillTableFromCsv(
39
+ db,
40
+ csvFile.split('/').pop()?.replace('.csv', '').replace('-', '_') as string,
41
+ csvFile,
42
+ );
43
+ }
44
+ }
45
+ await deployHdbViewFiles(db, this._dbPath);
46
+ this._deployed = true;
47
+ }
48
+ return db ?? cds.connect.to('db');
49
+ }
50
+
51
+ public async getDb() {
52
+ return this._db();
53
+ }
54
+
55
+ constructor(dbPath: string, options?: { csvFiles: string[] }) {
56
+ super();
57
+ this._csvFiles = options?.csvFiles || [];
58
+ this._dbPath = dbPath;
59
+ }
60
+
61
+ public async getTableColumns(table: string) {
62
+ if (TABLE_INFO[table]) return TABLE_INFO[table].map(info => info.name);
63
+ const tableInfo: [TableInfo] = await this.query(`PRAGMA table_info(${table})`);
64
+ TABLE_INFO[table] = tableInfo;
65
+ return tableInfo.map(info => info.name);
66
+ }
67
+
68
+ /**
69
+ * Get the primary key of the table
70
+ */
71
+ public async getTablePrimaryKey(table: string) {
72
+ if (PRIMARY_KEYS[table]) return PRIMARY_KEYS[table];
73
+ const tableInfo: [TableInfo] = await this.query(`PRAGMA table_info(${table})`);
74
+ TABLE_INFO[table] = tableInfo;
75
+ const primaryKey = tableInfo.find(info => info.pk === 1)?.name;
76
+ if (!primaryKey) throw new BdORMError(`No primary key found for table ${table}`);
77
+ PRIMARY_KEYS[table] = primaryKey;
78
+ return primaryKey;
79
+ }
80
+
81
+ /**
82
+ * Fills the database with data from the CSV files provided in the constructor
83
+ * note the table will be emptied before filling it with the data from the CSV file
84
+ */
85
+ public async fillTableFromCsvFile(table: string, csvFile: string) {
86
+ const db = await this._db();
87
+ await fillTableFromCsv(db, table, csvFile);
88
+ }
89
+ }
@@ -0,0 +1,75 @@
1
+ import { BdORMError } from '../../_/BdORMError';
2
+ import cds from '@sap/cds';
3
+ import csv from 'csv-parser';
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+
7
+ const log = (message: string) => {
8
+ console.log(`[BdOrmDbConnectionCapSqlite] ${message}`);
9
+ },
10
+ fillTableFromCsv = async (db: cds.DatabaseService, table: string, csvFile: string) => {
11
+ try {
12
+ const rows: Record<string, any>[] = [];
13
+ await new Promise<void>((resolve, reject) => {
14
+ fs.createReadStream(csvFile)
15
+ .pipe(csv({ separator: ';' }))
16
+ .on('data', (data: Record<string, any>) => rows.push(data))
17
+ .on('end', () => resolve())
18
+ .on('error', error => {
19
+ reject(error);
20
+ });
21
+ });
22
+ // empty db
23
+ await db.run(`DELETE FROM ${table}`);
24
+ for (const row of rows) {
25
+ const columns = Object.keys(row),
26
+ placeholders = columns.map(() => '?').join(',');
27
+ await db.run(
28
+ `INSERT INTO ${table} (${columns.join(', ')}) VALUES (${placeholders})`,
29
+ Object.values(row),
30
+ );
31
+ }
32
+ log(`Added ${rows.length} rows in ${table} from CSV file: ${csvFile}`);
33
+ } catch (error) {
34
+ throw new BdORMError(`Error while filling table from CSV: ${(error as Error).message}`);
35
+ }
36
+ },
37
+ findFiles = async (currentPath: string, extname: string) => {
38
+ let files: string[] = [];
39
+ //@ts-ignore
40
+ const entries = fs.readdirSync(currentPath, { withFileTypes: true });
41
+ //@ts-ignore
42
+ for (const entry of entries) {
43
+ const entryPath = path.join(currentPath, entry.name);
44
+ if (entry.isDirectory()) {
45
+ const subfiles = await findFiles(entryPath, extname);
46
+ files.push(...subfiles);
47
+ } else if (entry.isFile() && path.extname(entry.name) === extname) {
48
+ files.push(entryPath);
49
+ }
50
+ }
51
+ return files;
52
+ },
53
+ addCsvFilesFromDBFolder = async (db: cds.DatabaseService, dbPath: string) => {
54
+ try {
55
+ const csvFiles = await findFiles(dbPath, '.csv');
56
+ for (const csvFile of csvFiles) {
57
+ await fillTableFromCsv(
58
+ db,
59
+ csvFile.split('/').pop()?.replace('.csv', '').replace('-', '_') as string,
60
+ csvFile,
61
+ );
62
+ }
63
+ } catch (error) {
64
+ throw new BdORMError(`Error while adding CsvFilesFromDbFolder: ${(error as Error).message}`);
65
+ }
66
+ },
67
+ deployHdbViewFiles = async (db: cds.DatabaseService, dbPath: string) => {
68
+ const hdbViewFiles = await findFiles(dbPath, '.hdbview');
69
+ for (const hdbViewFile of hdbViewFiles) {
70
+ const hdbView = fs.readFileSync(hdbViewFile, 'utf8');
71
+ const m = await db.run(`create ${hdbView}`);
72
+ log(`Deployed HDB view from file: ${hdbViewFile}`);
73
+ }
74
+ };
75
+ export { addCsvFilesFromDBFolder, fillTableFromCsv, findFiles, log, deployHdbViewFiles };
@@ -0,0 +1,41 @@
1
+ import BdOrmDbConnectionCapSqlite from './BdOrmDbConnectionCapSqlite';
2
+
3
+ describe('bd-orm baseORMCrud', () => {
4
+ const dbConnection = new BdOrmDbConnectionCapSqlite(__dirname + '/../test-assets/db');
5
+ it('check if csv import has worked and if read works', async () => {
6
+ const { firstname } = await dbConnection.read('BDORM_USER', 2);
7
+ expect(firstname).toBe('Barry');
8
+ });
9
+ it('create worked', async () => {
10
+ const user = await dbConnection.create('BDORM_USER', { firstname: 'John', lastname: 'Wayne' });
11
+ expect(user.firstname).toBe('John');
12
+ expect(user.lastname).toBe('Wayne');
13
+ expect(user.id).toBe(3);
14
+ });
15
+
16
+ it('update worked', async () => {
17
+ await dbConnection.update('BDORM_USER', { id: 1, firstname: 'Boomer' });
18
+ const { firstname } = await dbConnection.read('BDORM_USER', 1);
19
+ expect(firstname).toBe('Boomer');
20
+ });
21
+
22
+ it('delete worked', async () => {
23
+ const users = await dbConnection.list('BDORM_USER');
24
+ await dbConnection.delete('BDORM_USER', 1);
25
+ const deleted = await dbConnection.read('BDORM_USER', 1);
26
+ const usersAfterDelete = await dbConnection.list('BDORM_USER');
27
+ expect(deleted).toBeUndefined();
28
+ expect(usersAfterDelete).toHaveLength(users.length - 1);
29
+ });
30
+
31
+ it('query worked', async () => {
32
+ const users = await dbConnection.query('SELECT * FROM BDORM_USER WHERE id = 2');
33
+ expect(users[0].firstname).toBe('Barry');
34
+ });
35
+
36
+ it('query a view worked', async () => {
37
+ const user = await dbConnection.create('BDORM_USER', { firstname: 'Test', lastname: 'Persoon' });
38
+ const users = await dbConnection.query('SELECT * FROM USER_VIEW WHERE lastname = ?', ['Persoon']);
39
+ expect(users[0].fullname).toBe('Test Persoon');
40
+ });
41
+ });
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Use this class as a base class for all SQL database connections
3
+ * It provides methods to interact with the database, such as create, read, update, delete, and list records.
4
+ * It also provides methods to execute raw SQL queries and manage database connections.
5
+ *
6
+ * This class is not meant to be used directly, but rather as a base class for other database connection classes.
7
+ * make sure yo u implement the _db method to return the correct database connection
8
+ * and the getTableColumns and getTablePrimaryKey methods to return the correct table columns and primary key
9
+ */
10
+ import { BdORMError } from '../_/BdORMError';
11
+ import BdOrmDbConnection from '../_/BdOrmConnection';
12
+
13
+ abstract class BdOrmDbConnectionSQLBase extends BdOrmDbConnection {
14
+ protected async _db(): Promise<{ run: (query: string, values?: any[]) => Promise<any> }> {
15
+ throw new BdORMError(`_db not implemented for ${this.constructor.name}`);
16
+ }
17
+
18
+ public async close() {
19
+ throw new BdORMError(`close not implemented for ${this.constructor.name}`);
20
+ }
21
+
22
+ public async create(table: string, data: Record<string, any>) {
23
+ const columns = Object.keys(data),
24
+ placeholders = columns.map(() => '?').join(',');
25
+ const { lastInsertRowid }: { changes: number; lastInsertRowid: number } = await this.query(
26
+ `INSERT INTO ${table} (${columns.join(',')}) VALUES (${placeholders})`,
27
+ columns.map(column => data[column]),
28
+ );
29
+ const pk = await this.getTablePrimaryKey(table);
30
+ const result = await this.query(`SELECT * FROM ${table} WHERE ${pk} = ${lastInsertRowid}`);
31
+ return result[0];
32
+ }
33
+
34
+ public async delete(table: string, primaryKeyValue: string | number) {
35
+ const primaryKey = await this.getTablePrimaryKey(table);
36
+ await this.query(`DELETE FROM ${table} WHERE ${primaryKey} = ?`, [primaryKeyValue]);
37
+ }
38
+
39
+ public async getTableColumns(table: string): Promise<string[]> {
40
+ throw new BdORMError(`getTableColumns not implemented for ${this.constructor.name}`);
41
+ }
42
+
43
+ /**
44
+ * Get the primary key of the table
45
+ */
46
+ public async getTablePrimaryKey(table: string): Promise<string> {
47
+ throw new BdORMError(`getTablePrimaryKey not implemented for ${this.constructor.name}`);
48
+ }
49
+
50
+ public async list(
51
+ table: string,
52
+ {
53
+ filters,
54
+ columns = '*',
55
+ orderBy,
56
+ limit,
57
+ offset,
58
+ values = [],
59
+ }: {
60
+ columns?: string | string[];
61
+ filters?: Record<string, any> | string;
62
+ limit?: number;
63
+ offset?: number;
64
+ orderBy?: string;
65
+ values?: any[];
66
+ } = {},
67
+ ) {
68
+ let query = `SELECT ${columns} FROM ${table}`;
69
+ if (typeof filters === 'string') {
70
+ query += ` WHERE ${filters}`;
71
+ } else {
72
+ if (typeof filters === 'object' && Object.keys(filters).length > 0) {
73
+ values = [];
74
+ const whereClause = Object.keys(filters)
75
+ .map(key => `${key} = ?`)
76
+ .join(' AND ');
77
+ query += ` WHERE ${whereClause}`;
78
+ values.push(...Object.values(filters));
79
+ }
80
+ if (orderBy) query += ` ORDER BY ${orderBy}`;
81
+ if (limit) query += ` LIMIT ${limit}`;
82
+ if (offset) query += ` OFFSET ${offset}`;
83
+ }
84
+ return this.query(query, values);
85
+ }
86
+
87
+ public async query(query: string, escapedValues: any[] = []) {
88
+ const db = await this._db();
89
+ try {
90
+ return await db.run(query, escapedValues);
91
+ } catch (error) {
92
+ throw new BdORMError(
93
+ `Error executing db query: ${(error as Error)?.message}. \nQuery: ${query} \nValues: ${escapedValues}`,
94
+ );
95
+ }
96
+ }
97
+ /**
98
+ * Alias for query
99
+ */
100
+ public async run(query: string, escapedValues: any[] = []) {
101
+ return this.query(query, escapedValues);
102
+ }
103
+
104
+ public async read(table: string, primaryKeyValue: string | number, { primaryKey }: { primaryKey?: string } = {}) {
105
+ const pk = primaryKey ?? (await this.getTablePrimaryKey(table));
106
+ const result = await this.query(`SELECT * FROM ${table} WHERE ${pk} = ?`, [primaryKeyValue]);
107
+ return result?.[0] || undefined;
108
+ }
109
+
110
+ public async update(table: string, data: any) {
111
+ const setClause = Object.keys(data)
112
+ .map(key => `${key} = ?`)
113
+ .join(', '),
114
+ primaryKey = await this.getTablePrimaryKey(table),
115
+ primaryKeyValue = data[primaryKey];
116
+ if (!primaryKeyValue)
117
+ throw new BdORMError(`No primary key value found for table ${table}, data: ${JSON.stringify(data)}`);
118
+ await this.query(`UPDATE ${table} SET ${setClause} WHERE ${primaryKey} = ?`, [
119
+ ...Object.values(data),
120
+ primaryKeyValue,
121
+ ]);
122
+ }
123
+ }
124
+ export default BdOrmDbConnectionSQLBase;
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ import BdOrmDbConnectionCapSqlite from './dbConnections/BdOrmDbConnectionCapSqlite';
2
+ import BaseORMCrud from './_/BdORMCrud';
3
+ import BdOrmDbConnection from './_/BdOrmConnection';
4
+ import BdOrmDbConnectionCapHana from './dbConnections/BdOrmDbConnectionCapHana';
5
+ import BdOrmDbConnectionSQLBase from './dbConnections/BdOrmDbConnectionSQLBase';
6
+
7
+ export default class BdOrm extends BaseORMCrud {}
8
+ export { BdOrmDbConnection, BdOrmDbConnectionCapSqlite, BdOrmDbConnectionCapHana, BdOrmDbConnectionSQLBase };
@@ -0,0 +1,16 @@
1
+ import BdOrm from '..';
2
+
3
+ interface Post {
4
+ id: number;
5
+ title: string;
6
+ content: string;
7
+ userId: number;
8
+ }
9
+ class Post extends BdOrm {
10
+ static readonly DB_TABLE: string = 'posts';
11
+ async fetchUser() {
12
+ //TODO; //User.fetch
13
+ }
14
+ }
15
+
16
+ export default Post;
@@ -0,0 +1,18 @@
1
+ import BdOrm from '..';
2
+
3
+ interface User {
4
+ id: number;
5
+ firstname: string;
6
+ lastname: string;
7
+ fullname?: string; // view property
8
+ email: string;
9
+ dateCreated: string;
10
+ }
11
+ class User extends BdOrm {
12
+ static readonly DB_TABLE = 'bdorm_user';
13
+ static readonly DB_VIEW = 'user_view';
14
+ static readonly PROPERTIES_NOT_ALLOWED_TO_CHANGE = ['dateCreated'];
15
+ static readonly PROPERTIES_NOT_ALLOWED_TO_DUPLICATE = ['dateCreated'];
16
+ }
17
+
18
+ export default User;
@@ -0,0 +1,20 @@
1
+ namespace bdOrm;
2
+
3
+ entity User {
4
+ key id : Integer;
5
+ firstname : String(50);
6
+ lastname : String(50);
7
+ email : String(50);
8
+ dateCreated : DateTime default $now;
9
+ options : String(500);
10
+ deleted : DateTime;
11
+ }
12
+
13
+ entity Post {
14
+ key id : Integer;
15
+ userId : Integer;
16
+ title : String(50);
17
+ content : String(50);
18
+ dateCreated : DateTime default $now;
19
+ deleted : DateTime;
20
+ }
@@ -0,0 +1,3 @@
1
+ id;firstname;lastname;email;dateCreated;deleted
2
+ 1;John;Doe;john.doe@example.com;;
3
+ 2;Barry;Dam;barry.dam@example.com;;
@@ -0,0 +1,3 @@
1
+ view USER_VIEW AS
2
+
3
+ SELECT bdorm_user.*, firstname || ' ' || lastname as fullname FROM bdorm_user;
@@ -0,0 +1,24 @@
1
+ import { it, expect } from '@jest/globals';
2
+ export const expectErrorMessage = async (fn: () => Promise<unknown>, message: string) => {
3
+ try {
4
+ await fn();
5
+ //@ts-ignore
6
+ fail('Expected an error to be thrown');
7
+ } catch (error) {
8
+ //@ts-ignore (excepct = jest)
9
+ if (error instanceof Error) return expect(error.message).toContain(message);
10
+ console.log(error);
11
+ //@ts-ignore (fail = jest fail)
12
+ fail('error is not of type Error');
13
+ }
14
+ };
15
+
16
+ export const expectToBes = (tests: Record<string, { test: () => any; toBe: any }>) => {
17
+ Object.entries(tests).forEach(([title, { test, toBe }]) => {
18
+ it(`${title} returns ${toBe}`, () => {
19
+ const value = test();
20
+ expect(value).toBe(toBe);
21
+ expect(value).not.toBe('RANDOM VALUE 1234567890');
22
+ });
23
+ });
24
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "commonjs",
5
+ "lib": ["ES2022"],
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "outDir": "dist",
11
+ "allowJs": true,
12
+ "declaration": true
13
+ },
14
+ "include": ["src/**/*"],
15
+ "exclude": ["node_modules", "**/*.test.ts"]
16
+ }
@@ -0,0 +1,113 @@
1
+ const fs = require('fs');
2
+ const exec = require('child_process').exec;
3
+ const core = require('@actions/core');
4
+ const semver = require('semver');
5
+
6
+ const successColor = '\x1b[42m';
7
+ const errorColor = '\x1b[41m';
8
+
9
+ const packageJson = fs.readFileSync('./package.json', 'utf8');
10
+ const { name: packageName, version: packageVersion } = JSON.parse(packageJson);
11
+
12
+ const logResult = (message, { failed } = {}) => console.log(failed ? errorColor : successColor, message, '\x1b[0m');
13
+
14
+ exec(`npm view ${packageName} dist-tags --json`, (err, stdout) => {
15
+ let isFirstDeployment = false;
16
+
17
+ if (err) {
18
+ /* if the is an error with 'code E404', it means that there is no package
19
+ * with this name found in the registry, which means it is the first deployment!
20
+ * is the error someting else, we exit
21
+ */
22
+ if (!err.message.includes('code E404')) {
23
+ console.error(err);
24
+ process.exit(1); // Exit with error code
25
+ }
26
+ isFirstDeployment = true;
27
+ }
28
+
29
+ // check whether packageVersion is a proper semantic version
30
+ if (!semver.valid(packageVersion)) {
31
+ logResult('❌ De versie in het package.json is niet valide! Bekijk https://semver.org/ voor meer info.', {
32
+ failed: true,
33
+ });
34
+ process.exit(1); // Exit with error code
35
+ }
36
+
37
+ console.log(stdout);
38
+ // parse output of stdout, but keep in mind whether it is the first deployment or not!
39
+ const { beta, latest, next } = JSON.parse(
40
+ isFirstDeployment || stdout.trim().length === 0
41
+ ? JSON.stringify({ beta: undefined, latest: undefined, next: undefined })
42
+ : stdout.trim(),
43
+ );
44
+
45
+ console.log(`versiecheck:`);
46
+ console.log(` - laatst gedeployede latest versie: ${latest ?? 'geen eerdere release'}`);
47
+ console.log(` - laatste beta versie: ${beta ?? 'geen eerdere release'}`);
48
+ console.log(` - laatste next versie: ${next ?? 'geen eerdere release'}`);
49
+ console.log(`versie in package.json: ${packageVersion}`);
50
+
51
+ // this function will exit the process if local version is lower than on the registry
52
+ const verifyVersion = (version, errorMessage) => {
53
+ if (!version) {
54
+ // no version information available, falling back to default (0.0.0)
55
+ version = '0.0.0';
56
+ }
57
+ if (semver.lte(packageVersion, version)) {
58
+ logResult(`❌ ${errorMessage}`, { failed: true });
59
+ process.exit(1);
60
+ }
61
+ };
62
+
63
+ const prereleaseComponents = semver.prerelease(packageVersion);
64
+ const isPrerelease = !!prereleaseComponents;
65
+
66
+ /**
67
+ * we'll use this tag as output of this file. We need to determine what kind of version the package.json is using now..
68
+ * supported release kinds;
69
+ * - regular release. Example: 0.7.1 => publishtag 'latest'
70
+ * - beta release. Example: 1.3.0-beta.1 => publishtag 'beta'
71
+ * - next release. Example: 1.0.0-next.0 => publishtag 'next'
72
+ */
73
+ let publishTag;
74
+
75
+ if (!isPrerelease) {
76
+ verifyVersion(
77
+ latest,
78
+ `package.json versie is nog niet opgehoogd ten opzichte van laatste release op npm (${packageVersion} vs ${latest})`,
79
+ );
80
+ publishTag = 'latest';
81
+ }
82
+
83
+ if (isPrerelease) {
84
+ const [kind] = prereleaseComponents;
85
+ if (kind === 'beta') {
86
+ // beta version
87
+ verifyVersion(
88
+ beta,
89
+ `package.json versie is nog niet opgehoogd ten opzichte van laatste release op npm (${packageVersion} vs ${beta})`,
90
+ );
91
+ publishTag = 'beta';
92
+ } else if (kind === 'next') {
93
+ // next version
94
+ verifyVersion(
95
+ next,
96
+ `package.json versie is nog niet opgehoogd ten opzichte van laatste release op npm (${packageVersion} vs ${next})`,
97
+ );
98
+ publishTag = 'next';
99
+ } else {
100
+ console.error(
101
+ `een onbekend soort prerelease is gevonden; '${kind}'. We ondersteunen enkel 'next' en 'beta'`,
102
+ );
103
+ process.exit(1);
104
+ }
105
+ }
106
+
107
+ // if we've arrived here, we are sure the package.json version is a valid semver string and we determined our publish tag
108
+ // this is used for github actions
109
+ core.setOutput('publishtag', publishTag);
110
+ isFirstDeployment
111
+ ? logResult('✔ Eerste release van dit package!')
112
+ : logResult('✔ package.json versie is opgehoogd ten opzichte van de vorige versie!');
113
+ });