From c248d2c9763e5b0201cee84116a6e0af67765fe0 Mon Sep 17 00:00:00 2001 From: Darryl <118641404+cdsiats@users.noreply.github.com> Date: Wed, 5 Feb 2025 18:46:07 +0800 Subject: [PATCH 1/2] added feature to use json files in cli #7 4d --- packages/idea-transformer/src/Transformer.ts | 30 +- .../idea-transformer/tests/Terminal.test.ts | 11 + packages/idea-transformer/tests/schema.json | 896 ++++++++++++++++++ 3 files changed, 925 insertions(+), 12 deletions(-) create mode 100644 packages/idea-transformer/tests/schema.json diff --git a/packages/idea-transformer/src/Transformer.ts b/packages/idea-transformer/src/Transformer.ts index 3400d7a..5f3140a 100644 --- a/packages/idea-transformer/src/Transformer.ts +++ b/packages/idea-transformer/src/Transformer.ts @@ -25,8 +25,14 @@ export default class Transformer> { if (!fs.existsSync(this.input)) { throw Exception.for('Input file %s does not exist', this.input); } - //parse schema - const schema = parse(fs.readFileSync(this.input, 'utf8')); + // read input file + const content = fs.readFileSync(this.input, 'utf8'); + + // parse schema + const schema: SchemaConfig = path.extname(this.input) === '.json' + ? JSON.parse(content) // parse directly + : parse(content); // parse as normal + //look for use if (Array.isArray(schema.use)) { schema.use.forEach((file: string) => { @@ -39,13 +45,13 @@ export default class Transformer> { const child = transformer.schema; //soft merge the object values of enum, //type, model from parent to schema - if (child.prop) { - schema.prop = { ...child.prop, ...schema.prop }; + if (child?.prop) { + schema.prop = { ...child?.prop, ...schema.prop }; } - if (child.enum) { - schema.enum = { ...child.enum, ...schema.enum }; + if (child?.enum) { + schema.enum = { ...child?.enum, ...schema.enum }; } - if (child.type) { + if (child?.type) { //make sure there is a schema type schema.type = schema.type || {}; //loop through child types @@ -65,11 +71,11 @@ export default class Transformer> { } } } - if (child.model) { + if (child?.model) { //make sure there is a schema model schema.model = schema.model || {}; //loop through child types - for (const [ name, model ] of Object.entries(child.model)) { + for (const [ name, model ] of Object.entries(child?.model)) { const parent = schema.model[name]; //if type from child doesn't exist in schema (parent) //or if no parent or parent is not mutable @@ -110,15 +116,15 @@ export default class Transformer> { public async transform(extras?: T) { //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') { + if (!this.schema?.plugin || typeof this.schema?.plugin !== 'object') { throw Exception.for('No plugins defined in schema file'); } //loop through plugins - for (const plugin in this.schema.plugin) { + for (const plugin in this.schema?.plugin) { //determine the module path const module = this.loader.absolute(plugin); //get the plugin config - const config = this.schema.plugin[plugin] as Record; + const config = this.schema?.plugin[plugin] as Record; //load the callback let callback = this.loader.require(module); //check for default diff --git a/packages/idea-transformer/tests/Terminal.test.ts b/packages/idea-transformer/tests/Terminal.test.ts index e2543ca..c572db8 100644 --- a/packages/idea-transformer/tests/Terminal.test.ts +++ b/packages/idea-transformer/tests/Terminal.test.ts @@ -21,6 +21,17 @@ describe('Terminal Tests', () => { } }).timeout(20000); + it('Should run cli using json file', async () => { + const terminal = new Terminal(['transform', '-i', './schema.json'], { cwd }); + expect(terminal.cwd).to.equal(cwd); + await terminal.run(); + const out = path.join(cwd, 'out/enums.ts'); + const exists = fs.existsSync(out); + expect(exists).to.be.true; + if (exists) { + fs.unlinkSync(out); + } + }).timeout(20000); /* * UNIT TEST TO COVER THE UNCOVERED LINES */ diff --git a/packages/idea-transformer/tests/schema.json b/packages/idea-transformer/tests/schema.json new file mode 100644 index 0000000..74620fe --- /dev/null +++ b/packages/idea-transformer/tests/schema.json @@ -0,0 +1,896 @@ +{ + "plugin": { + "./in/make-enums": { + "lang": "ts", + "output": "./out/enums.ts" + } + }, + "model": { + "Profile": { + "name": "Profile", + "mutable": true, + "attributes": { + "label": [ + "Profile", + "Profiles" + ], + "suggested": [ + "[name]" + ], + "icon": [ + "user" + ] + }, + "columns": [ + { + "type": "String", + "name": "name", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Full Name" + ], + "searchable": true, + "field.text": true, + "is.required": [ + "Name is required" + ], + "list.detail": true, + "view.text": true + } + }, + { + "type": "String", + "name": "image", + "required": false, + "multiple": false, + "attributes": { + "label": [ + "Image" + ], + "field.url": true, + "list.image": [ + { + "width": 20, + "height": 20 + } + ], + "view.image": [ + { + "width": 100, + "height": 100 + } + ] + } + }, + { + "type": "String", + "name": "description", + "required": false, + "multiple": false, + "attributes": { + "label": [ + "Description" + ], + "field.textarea": true, + "list.none": true, + "view.text": true + } + }, + { + "type": "String", + "name": "type", + "required": false, + "multiple": false, + "attributes": { + "label": [ + "Type" + ], + "default": [ + "person" + ], + "filterable": true, + "field.text": true, + "list.lowercase": true, + "view.lowercase": true + } + }, + { + "type": "String", + "name": "roles", + "required": true, + "multiple": true, + "attributes": { + "label": [ + "Roles" + ], + "field.textlist": true, + "list.hide": true, + "view.tags": true + } + }, + { + "type": "String", + "name": "tags", + "required": true, + "multiple": true, + "attributes": { + "label": [ + "Tags" + ], + "field.tags": true, + "list.hide": true, + "view.tags": true + } + }, + { + "type": "Hash", + "name": "references", + "required": false, + "multiple": false, + "attributes": { + "label": [ + "References" + ], + "field.metadata": true, + "list.hide": true, + "view.metadata": true + } + }, + { + "type": "Boolean", + "name": "active", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Active" + ], + "generated": true, + "active": true, + "default": [ + true + ], + "list.hide": true, + "view.yesno": true + } + }, + { + "type": "Datetime", + "name": "created", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Created" + ], + "generated": true, + "created": true, + "spanable": true, + "sortable": true, + "default": [ + "now()" + ], + "list.date": [ + "m d, Y h:iA" + ], + "view.date": [ + "m d, Y h:iA" + ] + } + }, + { + "type": "Datetime", + "name": "updated", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Updated" + ], + "generated": true, + "updated": true, + "spanable": true, + "sortable": true, + "default": [ + "now()" + ], + "list.date": [ + "m d, Y h:iA" + ], + "view.date": [ + "m d, Y h:iA" + ] + } + }, + { + "type": "Auth", + "name": "auth", + "required": false, + "multiple": false, + "attributes": { + "label": [ + "Auth" + ] + } + }, + { + "type": "Connection", + "name": "connections", + "required": true, + "multiple": true, + "attributes": { + "label": [ + "Connections" + ] + } + }, + { + "type": "Connection", + "name": "memberships", + "required": true, + "multiple": true, + "attributes": { + "label": [ + "Memberships" + ] + } + }, + { + "type": "File", + "name": "files", + "required": true, + "multiple": true, + "attributes": { + "label": [ + "Files" + ] + } + } + ] + }, + "Auth": { + "name": "Auth", + "mutable": true, + "attributes": { + "label": [ + "Auth", + "Auths" + ], + "suggested": [ + "[username]" + ], + "icon": [ + "lock" + ] + }, + "columns": [ + { + "type": "String", + "name": "id", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "ID" + ], + "id": true, + "generated": true, + "default": [ + "cuid()" + ], + "list.char": [ + { + "hellip": false, + "length": 8 + } + ] + } + }, + { + "type": "String", + "name": "profileId", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Profile" + ], + "filterable": true, + "field.relation": [ + "Profile", + "id" + ], + "is.required": [ + "Profile is required" + ], + "list.relation": [ + "Profile" + ], + "view.relation": [ + "Profile" + ] + } + }, + { + "type": "String", + "name": "username", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Username" + ], + "unique": true, + "searchable": true, + "filterable": true, + "field.text": true, + "is.required": [ + "Username is required" + ], + "is.cge": [ + 5, + "Should more than 5 characters" + ], + "list.detail": true, + "view.text": true + } + }, + { + "type": "String", + "name": "email", + "required": false, + "multiple": false, + "attributes": { + "label": [ + "Email Address" + ], + "unique": true, + "searchable": true, + "filterable": true, + "field.email": true, + "is.email": [ + "Should be a valid email address" + ], + "list.text": true, + "view.email": true + } + }, + { + "type": "String", + "name": "phone", + "required": false, + "multiple": false, + "attributes": { + "label": [ + "Phone Number" + ], + "unique": true, + "searchable": true, + "filterable": true, + "field.text": true, + "is.pattern": [ + "/^\\+[0-9]{0,3} [0-9]+$/", + "Should be a valid phone number" + ], + "list.text": true, + "view.phone": true + } + }, + { + "type": "String", + "name": "password", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Password" + ], + "field.password": true, + "is.required": [ + "Password is required" + ] + } + }, + { + "type": "String", + "name": "twofa", + "required": false, + "multiple": false, + "attributes": { + "label": [ + "2FA" + ], + "field.text": true + } + }, + { + "type": "Int", + "name": "verified", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Verified" + ], + "generated": true, + "default": [ + 0 + ] + } + }, + { + "type": "Datetime", + "name": "lastLogin", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Last Logged In" + ], + "generated": true, + "default": [ + "now()" + ], + "list.date": [ + "m d, Y h:iA" + ], + "view.date": [ + "m d, Y h:iA" + ] + } + }, + { + "type": "Boolean", + "name": "active", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Active" + ], + "generated": true, + "active": true, + "default": [ + true + ], + "list.yesno": true, + "view.yesno": true + } + }, + { + "type": "Datetime", + "name": "created", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Created" + ], + "generated": true, + "created": true, + "spanable": true, + "sortable": true, + "default": [ + "now()" + ], + "list.date": [ + "m d, Y h:iA" + ], + "view.date": [ + "m d, Y h:iA" + ] + } + }, + { + "type": "Datetime", + "name": "updated", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Updated" + ], + "generated": true, + "updated": true, + "spanable": true, + "sortable": true, + "default": [ + "now()" + ], + "list.date": [ + "m d, Y h:iA" + ], + "view.date": [ + "m d, Y h:iA" + ] + } + }, + { + "type": "Profile", + "name": "profile", + "required": true, + "multiple": false, + "attributes": { + "relation": [ + { + "local": "profileId", + "foreign": "id" + } + ] + } + } + ] + }, + "Connection": { + "name": "Connection", + "mutable": true, + "attributes": { + "label": [ + "Connection", + "Connections" + ], + "suggested": [ + "[owner.name] - [member.name]" + ], + "icon": [ + "users" + ] + }, + "columns": [ + { + "type": "String", + "name": "ownerId", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Owner" + ], + "id": true, + "relation": [ + "Profile", + "id" + ], + "is.required": [ + "Owner is required" + ] + } + }, + { + "type": "String", + "name": "memberId", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Member" + ], + "id": true, + "relation": [ + "Profile", + "id" + ], + "is.required": [ + "Member is required" + ] + } + }, + { + "type": "Roles", + "name": "role", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Role" + ], + "default": [ + "MEMBER" + ], + "field.text": true + } + }, + { + "type": "String", + "name": "tags", + "required": true, + "multiple": true, + "attributes": { + "label": [ + "Tags" + ], + "field.tags": true, + "list.hide": true, + "view.tags": true + } + }, + { + "type": "Boolean", + "name": "active", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Active" + ], + "generated": true, + "active": true, + "default": [ + true + ], + "list.yesno": true, + "view.yesno": true + } + }, + { + "type": "Datetime", + "name": "created", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Created" + ], + "generated": true, + "created": true, + "spanable": true, + "sortable": true, + "default": [ + "now()" + ], + "list.date": [ + "m d, Y h:iA" + ], + "view.date": [ + "m d, Y h:iA" + ] + } + }, + { + "type": "Datetime", + "name": "updated", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Updated" + ], + "generated": true, + "updated": true, + "spanable": true, + "sortable": true, + "default": [ + "now()" + ], + "list.date": [ + "m d, Y h:iA" + ], + "view.date": [ + "m d, Y h:iA" + ] + } + }, + { + "type": "Profile", + "name": "owner", + "required": true, + "multiple": false, + "attributes": { + "relation": [ + { + "name": "connections", + "local": "ownerId", + "foreign": "id" + } + ] + } + }, + { + "type": "Profile", + "name": "member", + "required": true, + "multiple": false, + "attributes": { + "relation": [ + { + "name": "memberships", + "local": "memberId", + "foreign": "id" + } + ] + } + } + ] + }, + "File": { + "name": "File", + "mutable": false, + "attributes": { + "label": [ + "File", + "Files" + ], + "suggested": [ + "[name]" + ], + "icon": [ + "file" + ] + }, + "columns": [ + { + "type": "String", + "name": "id", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "ID" + ], + "id": true, + "generated": true, + "default": [ + "cuid()" + ], + "list.char": [ + { + "hellip": false, + "length": 8 + } + ] + } + }, + { + "type": "String", + "name": "profileId", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Profile" + ], + "filterable": true, + "field.relation": [ + "Profile", + "id" + ], + "is.required": [ + "Profile is required" + ] + } + }, + { + "type": "String", + "name": "name", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Name" + ], + "searchable": true, + "field.text": true, + "is.required": [ + "Name is required" + ], + "list.detail": true, + "view.text": true + } + }, + { + "type": "String", + "name": "url", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "URL" + ], + "searchable": true, + "field.url": true, + "is.required": [ + "URL is required" + ], + "view.link": true + } + }, + { + "type": "String", + "name": "tags", + "required": true, + "multiple": true, + "attributes": { + "label": [ + "Tags" + ], + "field.tags": true, + "list.hide": true, + "view.tags": true + } + }, + { + "type": "Boolean", + "name": "active", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Active" + ], + "generated": true, + "active": true, + "default": [ + true + ], + "list.yesno": true, + "view.yesno": true + } + }, + { + "type": "Datetime", + "name": "created", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Created" + ], + "generated": true, + "created": true, + "spanable": true, + "sortable": true, + "default": [ + "now()" + ], + "list.date": [ + "m d, Y h:iA" + ], + "view.date": [ + "m d, Y h:iA" + ] + } + }, + { + "type": "Datetime", + "name": "updated", + "required": true, + "multiple": false, + "attributes": { + "label": [ + "Updated" + ], + "generated": true, + "updated": true, + "spanable": true, + "sortable": true, + "default": [ + "now()" + ], + "list.date": [ + "m d, Y h:iA" + ], + "view.date": [ + "m d, Y h:iA" + ] + } + }, + { + "type": "Profile", + "name": "profile", + "required": true, + "multiple": false, + "attributes": { + "relation": [ + { + "local": "profileId", + "foreign": "id" + } + ] + } + } + ] + } + } +} \ No newline at end of file From 80f112647696e5a891d1ced8c3f06e8b37848cb6 Mon Sep 17 00:00:00 2001 From: Darryl <118641404+cdsiats@users.noreply.github.com> Date: Wed, 5 Feb 2025 23:26:37 +0800 Subject: [PATCH 2/2] fixed comment formatting, removed optional chaining #7 1h --- packages/idea-transformer/src/Transformer.ts | 32 ++++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/idea-transformer/src/Transformer.ts b/packages/idea-transformer/src/Transformer.ts index 5f3140a..67e7c7e 100644 --- a/packages/idea-transformer/src/Transformer.ts +++ b/packages/idea-transformer/src/Transformer.ts @@ -25,14 +25,14 @@ export default class Transformer> { if (!fs.existsSync(this.input)) { throw Exception.for('Input file %s does not exist', this.input); } - // read input file + //read input file const content = fs.readFileSync(this.input, 'utf8'); - - // parse schema + //parse schema const schema: SchemaConfig = path.extname(this.input) === '.json' - ? JSON.parse(content) // parse directly - : parse(content); // parse as normal - + //parse directly + ? JSON.parse(content) + //parse as normal + : parse(content); //look for use if (Array.isArray(schema.use)) { schema.use.forEach((file: string) => { @@ -45,13 +45,13 @@ export default class Transformer> { const child = transformer.schema; //soft merge the object values of enum, //type, model from parent to schema - if (child?.prop) { - schema.prop = { ...child?.prop, ...schema.prop }; + if (child.prop) { + schema.prop = { ...child.prop, ...schema.prop }; } - if (child?.enum) { - schema.enum = { ...child?.enum, ...schema.enum }; + if (child.enum) { + schema.enum = { ...child.enum, ...schema.enum }; } - if (child?.type) { + if (child.type) { //make sure there is a schema type schema.type = schema.type || {}; //loop through child types @@ -71,11 +71,11 @@ export default class Transformer> { } } } - if (child?.model) { + if (child.model) { //make sure there is a schema model schema.model = schema.model || {}; //loop through child types - for (const [ name, model ] of Object.entries(child?.model)) { + for (const [ name, model ] of Object.entries(child.model)) { const parent = schema.model[name]; //if type from child doesn't exist in schema (parent) //or if no parent or parent is not mutable @@ -116,15 +116,15 @@ export default class Transformer> { public async transform(extras?: T) { //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') { + if (!this.schema.plugin || typeof this.schema.plugin !== 'object') { throw Exception.for('No plugins defined in schema file'); } //loop through plugins - for (const plugin in this.schema?.plugin) { + for (const plugin in this.schema.plugin) { //determine the module path const module = this.loader.absolute(plugin); //get the plugin config - const config = this.schema?.plugin[plugin] as Record; + const config = this.schema.plugin[plugin] as Record; //load the callback let callback = this.loader.require(module); //check for default