Skip to content

Commit d013b5c

Browse files
authored
chore:migrate to esm (#87)
* wip * fixed some tests * fix: used async API from fs * removed temporarily test coverage infra --------- Co-authored-by: Pal, Sayan <[email protected]>
1 parent 706f56c commit d013b5c

25 files changed

+753
-1974
lines changed

.eslintrc.js .eslintrc.cjs

File renamed without changes.

package-lock.json

+612-1,832
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+25-24
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@
22
"name": "@netatwork/odata-edm-generator",
33
"version": "1.0.0-7",
44
"description": "OData EDM generator",
5-
"typings": "dist/types/decorators",
6-
"main": "dist/cjs/api/decorators.js",
7-
"module": "dist/esm/decorators.js",
5+
"type": "module",
6+
"exports": {
7+
"import": "./dist/esm/api/decorators.js"
8+
},
9+
"typings": "dist/types/api/decorators",
810
"bin": {
9-
"gen-edm": "dist/cjs/cli/index.js"
11+
"gen-edm": "dist/esm/cli/index.js"
1012
},
1113
"scripts": {
1214
"lint": "eslint . --ext .ts --cache",
1315
"prebuild": "rimraf dist && npm run lint",
14-
"build": "tsc && tsc -p tsconfig.esm.json",
16+
"build": "tsc",
1517
"dev": "tsc -w --preserveWatchOutput",
16-
"test": "nyc --nycrc-path ./tests/nyc.config.js mocha --config ./tests/.mocharc.js",
17-
"test:dev": "cross-env DEV=true nyc --nycrc-path ./tests/nyc.config.js mocha --config ./tests/.mocharc.js --bail"
18+
"pretest": "tsc -p tests/tsconfig.json",
19+
"test": "mocha --config ./tests/.mocharc.cjs",
20+
"test:dev": "mocha --config ./tests/.mocharc.cjs --bail"
1821
},
1922
"repository": {
2023
"type": "git",
@@ -32,36 +35,34 @@
3235
},
3336
"homepage": "https://github.com/Netatwork-de/odata-edm-generator#readme",
3437
"devDependencies": {
35-
"@commitlint/cli": "^18.4.3",
36-
"@commitlint/config-conventional": "^18.6.0",
38+
"@commitlint/cli": "^19.0.3",
39+
"@commitlint/config-conventional": "^19.0.3",
3740
"@netatwork/mocha-utils": "^2.1.4",
38-
"@types/chai": "^4.3.4",
39-
"@types/diff": "^5.0.2",
41+
"@types/chai": "^4.3.12",
42+
"@types/diff": "^5.0.9",
4043
"@types/ejs": "^3.1.1",
4144
"@types/mocha": "^10.0.1",
4245
"@types/mock-fs": "^4.13.1",
43-
"@types/node": "^20.4.1",
44-
"@types/uuid": "^9.0.0",
45-
"@typescript-eslint/eslint-plugin": "^6.0.0",
46-
"@typescript-eslint/parser": "^6.0.0",
47-
"chai": "^4.3.7",
46+
"@types/node": "^20.11.25",
47+
"@types/uuid": "^9.0.8",
48+
"@typescript-eslint/eslint-plugin": "^7.1.1",
49+
"@typescript-eslint/parser": "^7.1.1",
50+
"chai": "^5.1.0",
4851
"colorette": "^2.0.19",
4952
"conventional-changelog-cli": "^4.1.0",
5053
"cross-env": "^7.0.3",
51-
"diff": "^5.1.0",
52-
"eslint": "^8.44.0",
53-
"eslint-plugin-import": "^2.26.0",
54-
"eslint-plugin-jsdoc": "^46.4.3",
55-
"eslint-plugin-mocha": "^10.1.0",
54+
"diff": "^5.2.0",
55+
"eslint": "^8.57.0",
56+
"eslint-plugin-import": "^2.29.1",
57+
"eslint-plugin-jsdoc": "^48.2.1",
58+
"eslint-plugin-mocha": "^10.4.0",
5659
"husky": "^9.0.11",
5760
"mocha": "^10.2.0",
5861
"mock-fs": "^5.2.0",
59-
"nyc": "^15.1.0",
6062
"rimraf": "^5.0.1",
61-
"source-map-support": "^0.5.21",
6263
"standard-version": "^9.5.0",
6364
"ts-node": "^10.9.1",
64-
"typescript": "^5.1.6",
65+
"typescript": "^5.4.2",
6566
"uuid": "^9.0.0"
6667
},
6768
"dependencies": {

src/cli/configuration.ts

+16-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
/* eslint-disable @typescript-eslint/no-non-null-assertion */
2-
import { existsSync, mkdirSync, statSync } from 'fs';
2+
import { promises as fs } from 'fs';
33
import { isAbsolute, resolve } from 'path';
4-
import { EndpointConfiguration, Logger } from './shared';
4+
import { EndpointConfiguration, Logger } from './shared.js';
5+
import { exists as exists } from './file-system-helper.js';
6+
import { pathToFileURL } from 'url';
57

68
export class Configuration {
79

@@ -14,7 +16,7 @@ export class Configuration {
1416
throw new Error('Configuration is not yet initialized.');
1517
}
1618

17-
public static createFromCLIArgs(args: string[]): Readonly<Configuration> {
19+
public static async createFromCLIArgs(args: string[]): Promise<Readonly<Configuration>> {
1820
if (this._instance !== null) {
1921
throw new Error('Configuration is already initialized.');
2022
}
@@ -33,11 +35,12 @@ export class Configuration {
3335
throw new Error('When providing a configuration file, the --config needs to be the first CLI argument.');
3436
}
3537
const configPath = resolve(process.cwd(), args[i + 1]);
36-
if (!existsSync(configPath) || !statSync(configPath).isFile()) {
38+
if (!await exists(configPath) || !(await fs.stat(configPath)).isFile()) {
3739
throw new Error(`The config file "${configPath}" does not exist.`);
3840
}
39-
// eslint-disable-next-line @typescript-eslint/no-var-requires
40-
instance.applyConfiguration(require(configPath) as ConfigSchema);
41+
let importedConfig = await import(pathToFileURL(configPath).href) as ConfigSchema & { default?: ConfigSchema };
42+
importedConfig = importedConfig.default as ConfigSchema ?? importedConfig;
43+
await instance.applyConfiguration(importedConfig);
4144
break;
4245
}
4346
case 'endpoint':
@@ -47,7 +50,7 @@ export class Configuration {
4750
instance.setEndpoints(JSON.parse(args[i + 1]) as string | EndpointConfiguration[]);
4851
break;
4952
case 'outputDir': {
50-
instance.setOutputDir(args[i + 1], true);
53+
await instance.setOutputDir(args[i + 1], true);
5154
break;
5255
}
5356
case 'quoteStyle':
@@ -78,8 +81,8 @@ export class Configuration {
7881

7982
private constructor() { /* noop */ }
8083

81-
private applyConfiguration(config: ConfigSchema) {
82-
this.setOutputDir(config.outputDir, false);
84+
private async applyConfiguration(config: ConfigSchema) {
85+
await this.setOutputDir(config.outputDir, false);
8386
this.setEndpointsFromConfig(config);
8487
this.setQuote(config.quoteStyle);
8588
this.setIndentation(config.indentSize);
@@ -110,12 +113,12 @@ export class Configuration {
110113
this.adjustOutputPaths();
111114
}
112115

113-
private setOutputDir(outputDir: string | undefined, throwError: boolean) {
116+
private async setOutputDir(outputDir: string | undefined, throwError: boolean) {
114117
if (!outputDir) { return; }
115118
const absolutePath: string = resolve(process.cwd(), outputDir);
116-
if (!existsSync(absolutePath)) {
117-
mkdirSync(absolutePath, { recursive: true });
118-
} else if (throwError && !statSync(absolutePath).isDirectory()) {
119+
if (!await exists(absolutePath)) {
120+
await fs.mkdir(absolutePath, { recursive: true });
121+
} else if (throwError && !(await fs.stat(absolutePath)).isDirectory()) {
119122
throw new Error(`The output path "${absolutePath}" is not a directory.`);
120123
}
121124
this.outputDir = absolutePath;

src/cli/file-system-helper.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { promises } from 'fs';
2+
3+
/**
4+
* Checks if a file or directory exists.
5+
* @param path
6+
* @returns `true` if the file or directory exists, `false` otherwise.
7+
*/
8+
export async function exists(path: string): Promise<boolean> {
9+
try {
10+
await promises.access(path);
11+
return true;
12+
} catch {
13+
return false;
14+
}
15+
}

src/cli/generator.ts

+14-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable @typescript-eslint/no-non-null-assertion */
2-
import { existsSync, writeFileSync, mkdirSync } from 'fs';
2+
import { promises as fs } from 'fs';
33
import { EOL } from 'os';
44
import { dirname } from 'path';
55
// eslint-disable-next-line @typescript-eslint/no-shadow
@@ -16,8 +16,9 @@ import {
1616
propertyComparator,
1717
PropertyInfo,
1818
ComplexTypeInfoSet,
19-
} from './shared';
20-
import { EdmTemplate, EndpointTemplate } from './templates';
19+
} from './shared.js';
20+
import { EdmTemplate, EndpointTemplate } from './templates.js';
21+
import { exists } from './file-system-helper.js';
2122

2223
// interface ImportInfo { ns: string; type: string; }
2324

@@ -94,7 +95,7 @@ export class $Generator {
9495
private readonly endpointTemplate = new EndpointTemplate();
9596
private readonly edmTemplate = new EdmTemplate();
9697

97-
public generateEdm(metadata: string, endpoints: Endpoint[], configuration: EndpointConfiguration): void {
98+
public async generateEdm(metadata: string, endpoints: Endpoint[], configuration: EndpointConfiguration): Promise<void> {
9899
const parsed = new DOMParser()
99100
.parseFromString(metadata, 'application/xml')
100101
.documentElement;
@@ -104,17 +105,17 @@ export class $Generator {
104105
}
105106
const edmInfo = this.generateCodeContent(parsed, endpoints, configuration);
106107
if (edmInfo !== null) {
107-
this.generateEdmFile(edmInfo);
108+
await this.generateEdmFile(edmInfo);
108109
}
109110
}
110111

111-
public generateEndpointsFile(endpoints: Endpoint[], configuration: EndpointConfiguration): void {
112+
public async generateEndpointsFile(endpoints: Endpoint[], configuration: EndpointConfiguration): Promise<void> {
112113
const path = getEndpointsPath(configuration);
113114
const dirName = dirname(path);
114-
if (!existsSync(dirName)) {
115-
mkdirSync(dirName, { recursive: true });
115+
if (!await exists(dirName)) {
116+
await fs.mkdir(dirName, { recursive: true });
116117
}
117-
writeFileSync(path, this.endpointTemplate.render(endpoints));
118+
await fs.writeFile(path, this.endpointTemplate.render(endpoints));
118119
}
119120

120121
private generateStringEnum(acc: EnumInfo[], enumType: Element, ignored: string[]): EnumInfo[] {
@@ -177,17 +178,17 @@ export class $Generator {
177178
return new EdmInfo(schema.getAttribute('Namespace')!, /* imports, */ entities, $complexTypes, enums, configuration);
178179
}
179180

180-
private generateEdmFile(edmInfo: EdmInfo) {
181+
private async generateEdmFile(edmInfo: EdmInfo) {
181182
const filePath = edmInfo.filePath;
182183

183184
const dirName = dirname(filePath);
184-
if (!existsSync(dirName)) {
185-
mkdirSync(dirName, { recursive: true });
185+
if (!await exists(dirName)) {
186+
await fs.mkdir(dirName, { recursive: true });
186187
}
187188

188189
const template = this.edmTemplate;
189190
const content = template.render(edmInfo);
190-
writeFileSync(filePath, content);
191+
await fs.writeFile(filePath, content);
191192
}
192193

193194
private generateEntityInfo(

src/cli/index.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#!/usr/bin/env node
22

33
import * as https from 'https';
4-
import { Configuration } from './configuration';
5-
import { $Generator } from './generator';
6-
import { Endpoint, Logger } from './shared';
4+
import { Configuration } from './configuration.js';
5+
import { $Generator } from './generator.js';
6+
import { Endpoint, Logger } from './shared.js';
77

88
function getData(url: string) {
99
return new Promise<string>((resolve, reject) => {
@@ -45,16 +45,16 @@ Options:
4545

4646
let generator: $Generator | null = null;
4747
try {
48-
const configuration = Configuration.createFromCLIArgs(args);
48+
const configuration = await Configuration.createFromCLIArgs(args);
4949
generator = new $Generator();
5050
for (const ep of configuration.endpoints) {
5151
const baseEndpoint = ep.url;
5252
const { value: endpoints } = JSON.parse(await getData(baseEndpoint)) as { value: Endpoint[] };
5353

54-
generator.generateEndpointsFile(endpoints, ep);
54+
await generator.generateEndpointsFile(endpoints, ep);
5555
Logger.info(`generated endpoints for ${baseEndpoint}.`);
5656

57-
generator.generateEdm(await getData(`${baseEndpoint}/$metadata`), endpoints, ep);
57+
await generator.generateEdm(await getData(`${baseEndpoint}/$metadata`), endpoints, ep);
5858
Logger.info(`generated EDM for ${baseEndpoint}.`);
5959
}
6060
} finally {

src/cli/shared.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { dirname, join, relative } from 'path';
2-
import { Configuration } from './configuration';
2+
import { Configuration } from './configuration.js';
33

44
export interface Endpoint {
55
name: string;

src/cli/templates.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Eta } from 'eta';
2-
import { Configuration } from './configuration';
3-
import { EdmInfo, Endpoint } from './shared';
2+
import { Configuration } from './configuration.js';
3+
import { EdmInfo, Endpoint } from './shared.js';
44

55
const defaultEndpointsTemplate = `/**
66
* This is a generated file. Please don't change this manually.

tests/.eslintrc.js tests/.eslintrc.cjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const path = require('path');
22

33
module.exports = {
44
extends: [
5-
'../.eslintrc.js',
5+
'../.eslintrc.cjs',
66
'plugin:mocha/recommended'
77
],
88
plugins: [

tests/.mocharc.cjs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
spec: './tests/.artifacts/dist/tests/**/*.spec.js',
3+
reporter: '@netatwork/mocha-utils/dist/JunitSpecReporter.js',
4+
reporterOptions: ['mochaFile=./tests/.artifacts/results.xml'],
5+
};

tests/.mocharc.js

-10
This file was deleted.

tests/configuration.spec.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { assert } from 'chai';
22
import mockFs from 'mock-fs';
33
import { join } from 'path';
4-
import { Configuration } from '../src/cli/configuration';
5-
import { EndpointConfiguration } from '../src/cli/shared';
4+
import { Configuration } from '../src/cli/configuration.js';
5+
import { EndpointConfiguration } from '../src/cli/shared.js';
66

77
describe('configuration', function () {
88
class TestData {
@@ -55,14 +55,14 @@ describe('configuration', function () {
5555
}
5656

5757
for (const data of getTestData()) {
58-
it(`createFromCLIArgs works correctly - ${data.toString()}`, function () {
58+
it(`createFromCLIArgs works correctly - ${data.toString()}`, async function () {
5959
try {
6060
const expectedOutputPath = data.expected.outputDir;
6161
mockFs({
6262
...(expectedOutputPath ? { [expectedOutputPath]: {} } : {})
6363
}, { createCwd: true });
6464

65-
const actual = Configuration.createFromCLIArgs(data.args);
65+
const actual = await Configuration.createFromCLIArgs(data.args);
6666
assert.deepStrictEqual(JSON.parse(JSON.stringify(actual)), data.expected);
6767
} finally {
6868
Configuration.dispose();

tests/data.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Endpoint } from '../src/cli/shared';
1+
import { Endpoint } from '../src/cli/shared.js';
22

33
export const standardEndpoints: Endpoint[] = [
44
{ name: 'People', kind: 'EntitySet', url: 'People' },

0 commit comments

Comments
 (0)