Skip to content

Commit 68c383a

Browse files
authored
chore: adds prettier as formatter (#12)
Also: * Changes the test to make it pass with a more fixed expected value * Formats the code based on formatter configs
1 parent 8a34931 commit 68c383a

File tree

8 files changed

+156
-130
lines changed

8 files changed

+156
-130
lines changed

.eslintrc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,8 @@
88
"eslint:recommended",
99
"plugin:@typescript-eslint/eslint-recommended",
1010
"plugin:@typescript-eslint/recommended"
11-
]
11+
],
12+
"rules": {
13+
"@typescript-eslint/no-explicit-any": "off"
14+
}
1215
}

.prettierrc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"arrowParens": "avoid",
3+
"printWidth": 80,
4+
"trailingComma": "es5",
5+
"tabWidth": 2,
6+
"semi": true,
7+
"singleQuote": true
8+
}

src/aibom/generator.ts

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,55 @@
1-
import fs from "node:fs";
2-
import path from "node:path";
1+
import fs from 'node:fs';
2+
import path from 'node:path';
33

44
export class AIBOMGenerator {
5-
generateAIBOM(modelData: any) { // eslint-disable-line @typescript-eslint/no-explicit-any
6-
const aibom = {
7-
bomFormat: "CycloneDX",
8-
components: [],
9-
dependencies: [],
10-
externalReferences: [],
11-
metadata: {
12-
component: {
13-
name: modelData.name,
14-
version: modelData.version,
15-
type: "machine-learning-model",
16-
description: modelData.description || "No description available",
17-
copyright: modelData.copyright || "NOASSERTION",
18-
// Use string literal for property name with hyphen
19-
"bom-ref": `pkg:huggingface/${modelData.author}/${modelData.name}@${modelData.version}`
20-
},
21-
properties: [
22-
{
23-
name: "primaryPurpose",
24-
value: modelData.primaryPurpose || "text-to-speech"
25-
},
26-
{
27-
name: "suppliedBy",
28-
value: modelData.author
29-
},
30-
{
31-
name: "licenses",
32-
value: modelData.license || "unknown"
33-
},
34-
{
35-
name: "downloadLocation",
36-
value: modelData.downloadUrl
37-
}
38-
]
39-
}
40-
};
5+
generateAIBOM(modelData: any) {
6+
const aibom = {
7+
bomFormat: 'CycloneDX',
8+
components: [],
9+
dependencies: [],
10+
externalReferences: [],
11+
metadata: {
12+
component: {
13+
name: modelData.name,
14+
version: modelData.version,
15+
type: 'machine-learning-model',
16+
description: modelData.description || 'No description available',
17+
copyright: modelData.copyright || 'NOASSERTION',
18+
// Use string literal for property name with hyphen
19+
'bom-ref': `pkg:huggingface/${modelData.author}/${modelData.name}@${modelData.version}`,
20+
},
21+
properties: [
22+
{
23+
name: 'primaryPurpose',
24+
value: modelData.primaryPurpose || 'text-to-speech',
25+
},
26+
{
27+
name: 'suppliedBy',
28+
value: modelData.author,
29+
},
30+
{
31+
name: 'licenses',
32+
value: modelData.license || 'unknown',
33+
},
34+
{
35+
name: 'downloadLocation',
36+
value: modelData.downloadUrl,
37+
},
38+
],
39+
},
40+
};
4141

42-
return aibom;
43-
}
42+
return aibom;
43+
}
4444

45-
saveAIBOM(aibom: any, filePath: string) { // eslint-disable-line @typescript-eslint/no-explicit-any
46-
const dir = path.join(process.cwd(), 'generated_aiboms');
47-
if (!fs.existsSync(dir)) {
48-
fs.mkdirSync(dir, { recursive: true });
49-
}
50-
// Replace slashes in filename with underscores to avoid subfolders
51-
const safeFileName = filePath.replace(/[\\/]/g, '_');
52-
const fullPath = path.join(dir, safeFileName);
53-
fs.writeFileSync(fullPath, JSON.stringify(aibom, null, 2));
45+
saveAIBOM(aibom: any, filePath: string) {
46+
const dir = path.join(process.cwd(), 'generated_aiboms');
47+
if (!fs.existsSync(dir)) {
48+
fs.mkdirSync(dir, { recursive: true });
5449
}
50+
// Replace slashes in filename with underscores to avoid subfolders
51+
const safeFileName = filePath.replace(/[\\/]/g, '_');
52+
const fullPath = path.join(dir, safeFileName);
53+
fs.writeFileSync(fullPath, JSON.stringify(aibom, null, 2));
54+
}
5555
}

src/index.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@ import { fetchTrendingModels } from './models/trendingModels';
22
import { AIBOMGenerator } from './aibom/generator';
33

44
async function main() {
5-
try {
6-
const trendingModels = await fetchTrendingModels();
7-
const aibomGenerator = new AIBOMGenerator();
5+
try {
6+
const trendingModels = await fetchTrendingModels();
7+
const aibomGenerator = new AIBOMGenerator();
88

9-
for (const model of trendingModels) {
10-
const aibom = aibomGenerator.generateAIBOM(model);
11-
console.log(`Generated AIBOM for model: ${model.name}`);
12-
// Save the AIBOM to a file
13-
aibomGenerator.saveAIBOM(aibom, `aibom_${model.name}.json`);
14-
}
15-
} catch (error) {
16-
console.error('Error generating AIBOMs:', error);
9+
for (const model of trendingModels) {
10+
const aibom = aibomGenerator.generateAIBOM(model);
11+
console.log(`Generated AIBOM for model: ${model.name}`);
12+
// Save the AIBOM to a file
13+
aibomGenerator.saveAIBOM(aibom, `aibom_${model.name}.json`);
1714
}
15+
} catch (error) {
16+
console.error('Error generating AIBOMs:', error);
17+
}
1818
}
1919

2020
main();
21-

src/models/trendingModels.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
import axios from 'axios';
22

33
export interface ModelMetadata {
4-
name: string;
5-
author: string;
6-
url: string;
4+
name: string;
5+
author: string;
6+
url: string;
77
}
88

99
// Define the expected structure for a model from the API
1010
interface HuggingFaceModel {
11-
modelId: string;
12-
author: string;
11+
modelId: string;
12+
author: string;
1313
}
1414

1515
export async function fetchTrendingModels(): Promise<ModelMetadata[]> {
16-
const response = await axios.get<HuggingFaceModel[]>('https://huggingface.co/api/models?sort=downloads&direction=-1');
17-
const models = response.data.slice(0, 30).map((model) => ({
18-
name: model.modelId,
19-
author: model.author,
20-
url: `https://huggingface.co/${model.modelId}`
21-
}));
22-
return models;
23-
}
16+
const response = await axios.get<HuggingFaceModel[]>(
17+
'https://huggingface.co/api/models?sort=downloads&direction=-1'
18+
);
19+
const models = response.data.slice(0, 30).map(model => ({
20+
name: model.modelId,
21+
author: model.author,
22+
url: `https://huggingface.co/${model.modelId}`,
23+
}));
24+
return models;
25+
}
26+

src/types/index.ts

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,44 @@
11
export interface ModelMetadata {
2+
name: string;
3+
author: string;
4+
url: string;
5+
version: string;
6+
description?: string;
7+
}
8+
9+
export interface AIBOM {
10+
bomFormat: string;
11+
components: Array<{
212
name: string;
3-
author: string;
4-
url: string;
513
version: string;
614
description?: string;
15+
authors: Array<{ name: string }>;
16+
licenses: Array<{ license: { id: string; url: string } }>;
17+
externalReferences: Array<{ type: string; url: string }>;
18+
modelCard?: {
19+
modelParameters: {
20+
architectureFamily: string;
21+
inputs: Array<{ format: string }>;
22+
outputs: Array<{ format: string }>;
23+
task: string;
24+
};
25+
properties: Array<{ name: string; value: string }>;
26+
};
27+
}>;
28+
dependencies?: Array<{
29+
dependsOn: Array<string>;
30+
ref: string;
31+
}>;
32+
metadata: {
33+
component: {
34+
name: string;
35+
version: string;
36+
type: string;
37+
};
38+
properties: Array<{ name: string; value: string }>;
39+
};
40+
serialNumber: string;
41+
specVersion: string;
42+
version: number;
743
}
844

9-
export interface AIBOM {
10-
bomFormat: string;
11-
components: Array<{
12-
name: string;
13-
version: string;
14-
description?: string;
15-
authors: Array<{ name: string }>;
16-
licenses: Array<{ license: { id: string; url: string } }>;
17-
externalReferences: Array<{ type: string; url: string }>;
18-
modelCard?: {
19-
modelParameters: {
20-
architectureFamily: string;
21-
inputs: Array<{ format: string }>;
22-
outputs: Array<{ format: string }>;
23-
task: string;
24-
};
25-
properties: Array<{ name: string; value: string }>;
26-
};
27-
}>;
28-
dependencies?: Array<{
29-
dependsOn: Array<string>;
30-
ref: string;
31-
}>;
32-
metadata: {
33-
component: {
34-
name: string;
35-
version: string;
36-
type: string;
37-
};
38-
properties: Array<{ name: string; value: string }>;
39-
};
40-
serialNumber: string;
41-
specVersion: string;
42-
version: number;
43-
}

test/test.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import test from "node:test";
2-
import assert from "node:assert";
3-
import { fetchTrendingModels } from "../src/models/trendingModels";
4-
import { AIBOMGenerator } from "../src/aibom/generator";
1+
import test from 'node:test';
2+
import assert from 'node:assert';
3+
import { fetchTrendingModels } from '../src/models/trendingModels';
4+
import { AIBOMGenerator } from '../src/aibom/generator';
55

6-
test("Generate something", async () => {
6+
test('Generate something', async () => {
77
const trendingModels = await fetchTrendingModels();
88
const aibomGenerator = new AIBOMGenerator();
99
const aibom = aibomGenerator.generateAIBOM(trendingModels.pop());
1010

11-
const expected = "facebook/contriever";
12-
assert.equal(expected, aibom.metadata.component.name);
11+
const expected = 'CycloneDX';
12+
assert.equal(expected, aibom.bomFormat);
1313
});
14-

tsconfig.json

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
11
{
22
"compilerOptions": {
3-
"target": "ES6",
4-
"module": "commonjs",
5-
"strict": true,
3+
"allowUnreachableCode": false,
4+
"allowUnusedLabels": false,
5+
"declaration": true,
66
"esModuleInterop": true,
7-
"skipLibCheck": true,
87
"forceConsistentCasingInFileNames": true,
9-
"outDir": "./dist",
10-
"rootDir": "./src"
8+
"module": "commonjs",
9+
"moduleResolution": "node",
10+
"newLine": "LF",
11+
"noEmitOnError": true,
12+
"noFallthroughCasesInSwitch": true,
13+
"noImplicitOverride": true,
14+
"noImplicitReturns": true,
15+
"noUnusedLocals": true,
16+
"outDir": "dist",
17+
"pretty": true,
18+
"rootDir": "src",
19+
"skipLibCheck": true,
20+
"strict": true,
21+
"strictNullChecks": true,
22+
"target": "ES6",
23+
"useUnknownInCatchVariables": false
1124
},
1225
"include": [
13-
"src/**/*"
26+
"src/**/*.ts"
1427
],
1528
"exclude": [
16-
"node_modules",
17-
"**/*.spec.ts"
29+
"node_modules"
1830
]
19-
}
31+
}
32+

0 commit comments

Comments
 (0)