xtend code generation calling entities from an xtext grammar - dsl

I am working on a code generator for my grammar that I have created:
Domainmodel:
(elements+=AbstractElement)*;
PackageDeclaration:
'package' name=QualifiedName '{'
(elements+=AbstractElement)*
'}';
AbstractElement:
PackageDeclaration | Type | Import;
QualifiedName:
ID ('-' ID)*;
QualifiedDate:
INT('-' INT)*
;
Import:
'import' importedNamespace=QualifiedNameWithWildcard;
QualifiedNameWithWildcard:
QualifiedName '.*'?;
Type:
(data+= DataType)* man+=Entity ;
DataType:
'tag' name=Tag;
Tag:
Hobbies='hobbies' | Work= 'work' |Fun='fun'
;
Entity:
name=Category '{'
feature+=Feature*
'}'
;
Feature:
component+=Man(',' component+=Opt)*
;
enum Category:
Blog='blog' | Article='articles'
;
Man:
name='title' '=' type=QualifiedName
;
Opt:
Tags|Date
;
Tags:
name='tags' '=' '['type= Tag(','tag+=Tag)*']'
|
name='tags' '=' '[' ']'
;
Date:
name='date' '=' type=QualifiedDate
;
I want my output of my code generator to look like this:
---
layout: post
title: "My Trip"
categories: blog
excerpt:
tags: [fun,hobbies]
image:
feature:
date: 2016-06-01T14:19:19-04:00
modified:
---
All I can get right is the static text, I can't seem to call: Category , title , tags , date
I've been trying for so long now but I can't seem to get anywhere, I keep getting strange errors which i don't understand
One of my attempts for just seeing what I can generate is:
class MyDslGenerator implements IGenerator2 {
def compile(Entity e)
{
'''
---
layout: post
title: "My Trip"
categories:«e.name»
excerpt:
tags: [fun,hobbies]
image:
feature:
date: 2016-06-01T14:19:19-04:00
modified:
---
'''
}
override doGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {
for (e : input.allContents.toIterable.filter(Entity)) {
fsa.generateFile(
e.generateName,
e.compile)
}
}
when I run the generator I don't get anything replaced by <>. I can't seem to figure it out.

is this a question on how to walk the AST. your grammar and thus the inferred metamodel is quite "bad" to walk so you may have to do something like
title: «(e.feature.head.component.head as Man).type»
so i recommend you to restructure your grammar/AST to fit the stuff you need.
you can set the encoding for the xtend/xtext plugin like this
tasks.withType(org.xtext.gradle.tasks.XtextGenerate) {
options.encoding = 'ISO-8859-1'
}
does that help?

/**
* generated by Xtext 2.10.0
*/
package org.xtext.example.mydsl.tests;
import com.google.inject.Inject;
import org.eclipse.xtend2.lib.StringConcatenation;
import org.eclipse.xtext.junit4.InjectWith;
import org.eclipse.xtext.junit4.XtextRunner;
import org.eclipse.xtext.junit4.util.ParseHelper;
import org.eclipse.xtext.xbase.lib.Exceptions;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xtext.example.mydsl.myDsl.Domainmodel;
import org.xtext.example.mydsl.tests.MyDslInjectorProvider;
#RunWith(XtextRunner.class)
#InjectWith(MyDslInjectorProvider.class)
#SuppressWarnings("all")
public class MyDslParsingTest {
#Inject
private ParseHelper<Domainmodel> parseHelper;
#Test
public void loadModel() {
try {
StringConcatenation _builder = new StringConcatenation();
_builder.append("Hello Xtext!");
_builder.newLine();
final Domainmodel result = this.parseHelper.parse(_builder);
Assert.assertNotNull(result);
} catch (Throwable _e) {
throw Exceptions.sneakyThrow(_e);
}
}
}

Related

Interpolate variable in multiline vanilla javascipt

Recently, I wanted to develop a plugin for javascipt for visual studio code. It's essence is to generate 3 files with template text in them. I stored the template text as a multiline string in a variable, but I never managed to insert the variable interpolation into the multiline string.
Code sample below:
const blocName = await vscode.window.showInputBox({
placeHolder: "Bloc name",
prompt: "Enter the BLoC name",
});
const blocNameLower = blocName.toLowerCase();
const bloc = 'import \'dart:async\';\n\
import \'package:${blocNameLower}_bloc/bloc.dart\'\;\n\
import \'package:meta/meta.dart\';\n\
\n\
part \'${blocNameLower}_event.dart\';\n\
part \'${blocNameLower}_state.dart\';\n\
\n\
class ${blockName}Bloc extends Bloc<${blockName}Event, ${blockName}State> {\n\
${blockName}Bloc() : super(${blockName}Initial()) {\n\
on<${blockName}Event>((event, emit) {\n\
// TODO: implement event handler\n\
});\n\
}\n\
}';
Let's assume input is Test:
Actual behavior:
import 'dart:async';
import 'package:${blocNameLower}_bloc/bloc.dart';
import 'package:meta/meta.dart';
part '**${blocNameLower}**_event.dart';
part '${blocNameLower}_state.dart';
class ${blockName}Bloc extends Bloc<${blockName}Event, ${blockName}State> {
${blockName}Bloc() : super(${blockName}Initial()) {
on<${blockName}Event>((event, emit) {
// TODO: implement event handler
});
}
}
Expected behavior:
import 'dart:async';
import 'package:test_bloc/bloc.dart';
import 'package:meta/meta.dart';
part '**test**_event.dart';
part 'test_state.dart';
class TestBloc extends Bloc<TestEvent, TestState> {
TestBloc() : super(TestInitial()) {
on<TestEvent>((event, emit) {
// TODO: implement event handler
});
}
}
Is there any chance to interpolate variable in multiline line..(as with 'part test_event.dart';) ?

DataGrip org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:

I am unable to run some basic groovy code with abstraction. I have read thru this link and auto generated pojos and rest controllers from Data Grip.
On DataGrip I right-click, hit "Scripted Extensions" and
select a Groovy file. If the file is written exactly as "Groovy Pojos.groovy" (see in link) then it works.
If I want to use some basic abstraction and designs around reusability it fails to work. Cant even get to import classes in Groovy.
Simple code snippet of what I tried
class abstract AGenerate {
abstract def getPackageName() ;
abstract def getFileSuffix() ;
abstract def generateClassFiles()
abstract def generate(output, className, fields) ;
def typeMapping = [
(~/(?i)int/) : "Integer",
(~/(?i)bigint/) : "Long",
(~/(?i)float/): "Double", : "Float",
(~/(?i)double|decimal|real/) : "Double",
(~/(?i)datetime|timestamp/) : "java.sql.Timestamp",
(~/(?i)date/) : "java.sql.Date",
(~/(?i)time/) : "java.sql.Time",
(~/(?i)/) : "String"
]
...
package com.companyname.autogenerate ;
import com.intellij.database.model.DasTable
import com.intellij.database.model.ObjectKind
import com.intellij.database.util.Case
import com.intellij.database.util.DasUtil
FILES.chooseDirectoryAndSave("Choose directory", "Choose where to store generated files") { dir ->
SELECTION.filter { it instanceof DasTable && it.getKind() == ObjectKind.TABLE }.each { generateFolderFromTable(it, dir) }
}
class GenerateEntityClass extends AGenerate {
def getFileSuffix() {
return "Entity.java"
}
def getPackageName() {
return "com.sample;" ;
}
...
Notice I have defined a super class AGenerate and then child classes GenerateEntityClass, I get a error when try to run AutoGenerate at the import line itself
import com.intellij.database.model.DasTable
import com.intellij.database.model.ObjectKind
import com.mycompany.autogenerate.GenerateEntityClass
def GenerateEntityClass entityClass = new GenerateEntityClass();
FILES.chooseDirectoryAndSave("Choose directory", "Choose where to store generated files") { dir ->
SELECTION.filter { it instanceof DasTable && it.getKind() == ObjectKind.TABLE }.each { entityClass.generateFolderFromTable(it, dir) }
}
I get an error
12:06 AM AutoGenerate.groovy:
org.codehaus.groovy.control.MultipleCompilationErrorsException:
startup failed: Script24.groovy: 4: unable to resolve class
com.companyname.autogenerate.GenerateEntityClass # line 4, column 1. import
com.companyname.autogenerate.GenerateEntityClass;
Edit: Folder Structure
Project
-->scripts
----->AutoGenerate.groovy (call this from DataGrip)
----->com
-------->companyname
----------->autogenerate
-------------->AGenerate.groovy
-------------->GenerateEntityClass.groovy
-->src
For some reason abstractions dont work. So I just separated the scripts in different files (ones that change and ones that done) and used a bash script to concat. For now this should work. Until someone answers this in a better way this works.

coordinates does not exist in type 'GeometryDataType'

This is a follow up on this question. Now I am using the point object correctly however I get this error:
src/actions/collectGpsData.ts:22:43 - error TS2322: Type '{ type: string; coordinates: any[]; }' is not assignable to type 'GeometryDataType'.
Object literal may only specify known properties, and '"coordinates"' does not exist in type 'GeometryDataType'.
22 place.location = { "type": "Point", "coordinates": [point.latitude, point.longitude] };
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Found 1 error.
import { Action } from "actionhero"; // No GeometryDataType sequelize.js definition
import { Place } from "../models/Place";
export class CollectGpsData extends Action {
constructor() {
super();
this.name = "collectGpsData";
this.description = "Collects GPS data and inserts it into the database";
this.outputExample = {};
this.inputs = {
gpsdata: {
required:true
}
}
}
async run(data) {
var GPSdata = data.params.gpsdata;
GPSdata.forEach(point => {
var place = new Place();
place.deviceimei = point.deviceimei;
place.location = { "type": "Point", "coordinates": [point.latitude, point.longitude] }; //error line
});
}
}
Why am I getting this error? and how can I avoid this error in the future?
I've answered it in your GitHub issue:
Hello #krlicmuhamed!
As #nainkunal933 noted, please include a complete code sample next time. The code you posted does not show how User is defined, for example. Please use a sequelize-sscce.
That said, I took the time to look into what's happening and tried to figure it out.
So, first of all, this issue is typescript-only. The code works fine in runtime. Please include this information directly next time.
I ventured into your stackoverflow question and comments and found this:
https://gist.github.com/krlicmuhamed/199c0bc3560a08718b553f3f609acbcd#file-places-ts-L22
Did you find any documentation instructing you to use this specific type explicitly here? If yes, please post the link so I can fix it. Regardless, I don't blame you because we really should have a set of recommended types to apply on each data type. It turns out GeometryDataType is not the correct type to use in this case.
The solution is to install #types/geojson:
npm install --save-dev #types/geojson
Then, import Geometry:
import type { Geometry } from '#types/geojson'
And then replace that line of code in which you put GeometryDataType with Geometry:
#AllowNull(false)
#Column(DataTypes.GEOMETRY)
- location: GeometryDataType;
+ location: Geometry;

RobinBuschmann/soap-typescript/soap-decorators Example

Can someone please give me a detailed example of RobinBuschmann/soap-typescript/soap-decorators Example. I am looking to create a wsdl xml for node-soap. The example given on github of RobinBuschmann/soap-typescript does not seem to work as is. I put the first three code snippets in a file called createWsdl.js and ran it with "node createWsdl.js" and I get an error. I suspect I am not doing the right thing. Can someone please help me or give me a detailed example that actually works.
I used node-soap and soap-decorators to communicate with Quickbooks. The following is from my app.ts file:
this.express.use(
'/soap',
soap(this.quickbooksController, {
overrideRootElement: {
namespace: '',
xmlnsAttributes: [
{
name: 'xmlns',
value: 'http://developer.intuit.com/'
}
]
}
})
);
The controller is annotated like so:
import { SoapOperation, SoapService } from 'soap-decorators';
import { AuthenticateRequest, AuthenticateResponse } from './model/authenticate.interface';
#SoapService({
portName: 'QBWebConnectorSvcSoap',
serviceName: 'QBWebConnectorSvc',
targetNamespace: 'http://developer.intuit.com/'
})
export class QuickbooksController {
#SoapOperation(AuthenticateResponse)
authenticate(data: AuthenticateRequest, res: (res: AuthenticateResponse) => any): void {
res({ authenticateResult: { string: ['', 'NVU'] } });
}
}
My request and response objects are decorated as XSD types:
import { XSDComplexType, XSDElement } from 'soap-decorators';
#XSDComplexType
export class AuthenticateRequest {
#XSDElement
strUserName: string;
#XSDElement
strPassword: string;
}
#XSDComplexType
class AuthenticateResult {
#XSDElement({ type: 'string' })
string: string[];
}
#XSDComplexType({ name: 'authenticateResponse' })
export class AuthenticateResponse {
#XSDElement
authenticateResult: AuthenticateResult;
}

StreamingTemplateEngine exception MissingPropertyException

How to avoid occurrence MissingPropertyException at absence of parameters from a template in Map and to replace not found values by null?
import groovy.text.StreamingTemplateEngine
import groovy.text.Template
class Test {
private static Writable binding(Map map, String string) {
Template template = new StreamingTemplateEngine().createTemplate(string)
return template.make(map)
}
static void main(String... args) {
def template = "\${test1} \${test2}"
def map = ["test1": "test1"]
print binding(map, template)
}
}
There is no configuration option to suppress this exception, however you can extend a map you pass to the template and change its behavior a bit. Consider following example:
import groovy.text.StreamingTemplateEngine
import groovy.text.Template
def string = '''
Dear <% out.print firstname %> ${lastname},
We <% if (accepted) out.print 'are pleased' else out.print 'regret' %>
to inform you that your paper entitled
'$title' was ${ accepted ? 'accepted' : 'rejected' }.
The conference committee.
'''
def map = [
firstname: 'test',
lastname: 'test',
accepted: true
]
Template template = new StreamingTemplateEngine().createTemplate(string)
println template.make(map)
It fails with the following exception:
Caught: groovy.text.TemplateExecutionException: Template execution error at line 4:
3: We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> to inform you that your paper entitled
--> 4: '$title' was ${ accepted ? 'accepted' : 'rejected' }.
5:
groovy.text.TemplateExecutionException: Template execution error at line 4:
3: We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> to inform you that your paper entitled
--> 4: '$title' was ${ accepted ? 'accepted' : 'rejected' }.
5:
at test.run(test.groovy:21)
Caused by: groovy.lang.MissingPropertyException: No such property: title for class: groovy.tmp.templates.StreamingTemplateScript1
... 1 more
It fails because we have defined 3 from 4 template variables (variable title is missing).
Solution: create wrapper for a Map
Let's fix it. We will do it by overriding map method containsKey(Object key) in a way that it always returns true (this method is used by the template engine and if it returns false, template engine throws an exception). We will create a wrapper class that encapsulates a map and delegates invocation of non existing methods to this wrapped class. We will call this class Bindings.
import groovy.text.StreamingTemplateEngine
import groovy.text.Template
class Bindings {
#Delegate private final Map map
Bindings(Map map) {
this.map = map
}
boolean containsKey(Object key) {
return true
}
}
def string = '''
Dear <% out.print firstname %> ${lastname},
We <% if (accepted) out.print 'are pleased' else out.print 'regret' %>
to inform you that your paper entitled
'$title' was ${ accepted ? 'accepted' : 'rejected' }.
The conference committee.
'''
def map = [
firstname: 'test',
lastname: 'test',
accepted: true
]
Template template = new StreamingTemplateEngine().createTemplate(string)
println template.make(new Bindings(map))
Output:
Dear test test,
We are pleased
to inform you that your paper entitled
'null' was accepted.
The conference committee.
There is no MissingPropertyException thrown anymore. However, as you can see, null is printed as null inside the String. If you would like to print an empty string instead, you can add Object get(Object key) method to Bindings and override its default behavior:
class Bindings {
#Delegate private final Map map
Bindings(Map map) {
this.map = map
}
boolean containsKey(Object key) {
return true
}
Object get(Object key) {
return map.getOrDefault(key, '')
}
}
If you do so, you will see the output similar to:
Dear test test,
We are pleased
to inform you that your paper entitled
'' was accepted.
The conference committee.
Hope it helps.
As an alternative, you can just use the groovy Map.withDefault method:
import groovy.text.StreamingTemplateEngine
import groovy.text.Template
def string = '''
Dear <% out.print firstname %> ${lastname},
We <% if (accepted) out.print 'are pleased' else out.print 'regret' %>
to inform you that your paper entitled
'$title' was ${ accepted ? 'accepted' : 'rejected' }.
The conference committee.
'''
def map = [
firstname: 'test',
lastname: 'test',
accepted: true
].withDefault { "<not found>" }
Template template = new StreamingTemplateEngine().createTemplate(string)
println template.make(map)
where the only change to the OPs code is the withDefault clause. Executing the above prints:
~> groovy test.groovy
Dear test test,
We are pleased
to inform you that your paper entitled
'<not found>' was accepted.
The conference committee.
As a side note, I wrote the streaming template engine as a contribution and a response to the limitations of the other template engines at the time a few years back. Glad to see it being used!
Though in hindsight it's far from perfect. Writing another one with a better internal approach has been on my list for aeons.

Resources