Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 50 additions & 33 deletions packages/idea-transformer/src/Transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ export default class Transformer<T extends Record<string, unknown>> {
schema.use.forEach((file: string) => {
const absolute = this.loader.absolute(file);
const dirname = path.dirname(absolute);
const transformer = new Transformer(absolute, {
cwd: dirname,
fs: this.loader.fs
const transformer = new Transformer(absolute, {
cwd: dirname,
fs: this.loader.fs
});
const child = transformer.schema;
//soft merge the object values of enum,
Expand All @@ -49,16 +49,18 @@ export default class Transformer<T extends Record<string, unknown>> {
//make sure there is a schema type
schema.type = schema.type || {};
//loop through child types
for (const [ name, type ] of Object.entries(child.type)) {
for (const [name, type] of Object.entries(child.type)) {
const parent = schema.type[name];
//if type from child doesn't exist in schema (parent)
if (!parent) {
//add it to schema (parent)
schema.type[name] = type;
continue;
//if parent isnt final
} else if (parent.mutable) {
//soft merge type into parent
//if parent isnt final
}
// If the parent is mutable, perform a soft merge
if (parent.mutable ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove space after mutable

//soft merge type ito parent
this._merge(parent, type);
}
}
Expand All @@ -70,11 +72,13 @@ export default class Transformer<T extends Record<string, unknown>> {
for (const [ name, model ] of Object.entries(child.model)) {
const parent = schema.model[name];
//if type from child doesn't exist in schema (parent)
if (!parent) {
// If no parent or parent is not mutable, add the model
// to the schema (parent)
if (!parent || !parent.mutable) {
//add it to schema (parent)
schema.model[name] = model;
continue;
//if parent isnt final
//if parent isnt final
} else if (parent.mutable) {
//soft merge type into parent
this._merge(parent, model);
Expand All @@ -94,18 +98,20 @@ export default class Transformer<T extends Record<string, unknown>> {

/**
* Preloads the input
*/
*/
constructor(input: string, options: TransformerOptions = {}) {
this.loader = new FileLoader(options.fs || new NodeFS(), options.cwd);
this.input = this.loader.absolute(input);
}


/**
* Transform all plugins
*/
public transform(extras?: T) {
//if no plugins defined throw error
if (!this.schema.plugin) {
// Ensure the plugin not exists or is not object if the
// conditions are true will throw an error.
if (!this.schema.plugin || typeof this.schema.plugin !== 'object') {
throw Exception.for('No plugins defined in schema file');
}
//loop through plugins
Expand All @@ -123,11 +129,11 @@ export default class Transformer<T extends Record<string, unknown>> {
//check if it's a function
if (typeof callback === 'function') {
//call the callback
callback({
...extras,
config,
schema: this.schema,
cwd: this.loader.cwd
callback({
...extras,
config,
schema: this.schema,
cwd: this.loader.cwd
});
}
//dont do anything else if it's not a function
Expand All @@ -139,26 +145,37 @@ export default class Transformer<T extends Record<string, unknown>> {
* This is the logic for use() directive in schema files.
*/
protected _merge(parent: TypeConfig, child: TypeConfig) {
//type exists in schema (parent)
//let's soft merge the attributes and columns
const { attributes = {}, columns = [] } = child;
//merge child attributes with schema attributes
//where schema attributes take precedence
parent.attributes = {
...attributes,
...parent.attributes
};
//merge child columns with schema columns
//where schema columns take precedence
columns.reverse().forEach(column => {
//To ensure that the column of both the parent and child objects is
//initialized as an array if it is undefined or null.
parent.columns = parent.columns || [];
child.columns = child.columns || [];
// Merge the attributes of the child into parent
// and also ensure that the attributes of child is only merged if
// they are valid, not null and not undefined
if (typeof child.attributes === 'object'
&& child.attributes !== null
&& child.attributes !== undefined) {
parent.attributes = {
...child.attributes,
...parent.attributes,
};
}
// The column of the child is densn't exist in the parent,It will
// add to the start of the parent column. If the column already
// exist in the parent, make a merged with the parent and child
child.columns.reverse().forEach(column => {
const existingColumn = parent.columns.find(c => c.name === column.name)
//find the same column in parent and if not found,
if (parent.columns.findIndex(
c => c.name === column.name
) === -1) {
if (!existingColumn) {
//add it
parent.columns.unshift(column);
} else {
// Deep merge attributes within the column if they exist
existingColumn.attributes = {
...column.attributes,
...existingColumn.attributes,
};
}
//it exists in the parent, so parent takes precedence...
});
}
}
13 changes: 13 additions & 0 deletions packages/idea-transformer/tests/Terminal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,17 @@ describe('Terminal Tests', () => {
fs.unlinkSync(out);
}
}).timeout(20000);

/*
* UNIT TEST TO COVER THE UNCOVERED LINES
*/

// Line 22
it('Should use default options when options parameter is omitted', () => {
const args = ['transform', '-i', './schema.idea'];
const terminal = new Terminal(args);
expect(terminal.cwd).to.equal(process.cwd());
});


});
51 changes: 48 additions & 3 deletions packages/idea-transformer/tests/Transformer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { describe, it } from 'mocha';
import { expect } from 'chai';
//for testing
import Transformer from '../src/Transformer';
import { TypeConfig } from '@stackpress/idea-parser';
//resusable variables
const cwd = __dirname;
const idea = path.resolve(cwd, 'schema.idea');
Expand All @@ -25,12 +26,15 @@ describe('Transformer Tests', () => {
expect(actual.prop && 'Config' in actual.prop).to.be.true;
//merge checks
expect(actual.model?.Profile?.columns[0].name).to.equal('id');
expect(actual.model?.Profile?.columns[1].name).to.equal('addresses');
expect(actual.model?.Profile?.columns[1].name).to.equal('addresses');
expect(actual.model?.Profile?.columns[2].attributes.label?.[0]).to.equal('Full Name');
//final checks
expect(
actual.model?.File?.columns.find(c => c.name === 'references')
).to.be.undefined;
// I'll exchange the references to the Hash to fix the issue
// I will use Hash to provide the unique identifier
// to cover the Line 80 - 81: schema.mode[name] = model; continue;
actual.model?.File?.columns.find(c => c.name === 'Hash')
).to.be.undefined;
}).timeout(20000);

it('Should make enums', () => {
Expand All @@ -43,4 +47,45 @@ describe('Transformer Tests', () => {
fs.unlinkSync(out);
}
}).timeout(20000);


/*
* UNIT TEST TO COVER THE UNCOVERED LINES
*/

// LINE 26
it('Should throw an error if the input file does not exist', () => {
const nonExistentPath = path.resolve(cwd, 'nonexistent.idea');
const transformer = new Transformer(nonExistentPath, { cwd });
expect(() => transformer.schema).to.throw(`Input file ${nonExistentPath} does not exist`);
});

// lINE 109
it('Should throw an error if no plugins are defined in the schema file', () => {
// Create a schema with no plugins
const transformer = new Transformer(idea, { cwd });
// Temporarily set the schema.plugins to undefined or an empty object to simulate the missing plugins
transformer['_schema'] = {
...transformer['_schema'],
plugin: undefined,
};
expect(() => transformer.transform()).to.throw('No plugins defined in schema file');
});


/*
* ADD MORE UNIT TEST TO ACHIEVE 85%
*/

it('Should merge child attributes into parent attributes', () => {
const transformer = new Transformer(idea, { cwd });
const parentType = { attributes: { name: 'parent' } };
const childType = { attributes: { name: 'child' } };
transformer['_merge'](parentType as unknown as TypeConfig, childType as unknown as TypeConfig);
expect(parentType.attributes).to.deep.equal({ name: 'parent' });
});




});
Loading