Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript implementation #20

Merged
merged 54 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
0258f72
Scaffold basic TypeScript generator
jgaehring Feb 8, 2024
44b9b04
Copy static files from old repository
jgaehring Feb 8, 2024
f8e9184
Remove semantizer symlinks in package-lock.json
jgaehring Feb 9, 2024
0217cbf
Re-export php license from common
jgaehring Feb 9, 2024
f381ea5
Export classes & interfaces as defaults
jgaehring Feb 9, 2024
e23f7d7
Generate TS class heritage
jgaehring Feb 14, 2024
af7734f
Generate TS imports
jgaehring Feb 13, 2024
c540eec
Generate TS base class connector member
jgaehring Feb 14, 2024
2cbd972
Generate TS constructor & owned operations
jgaehring Feb 14, 2024
61300d6
Generate interface heritage
jgaehring Feb 14, 2024
bcf6039
Generate TS constructor body
jgaehring Feb 18, 2024
8833fe2
Reorganize operation templates
jgaehring Feb 19, 2024
65ee3ab
Copy remaining static files from orig repo
jgaehring Feb 20, 2024
35042c6
Generate TS interface operations
jgaehring Feb 20, 2024
81ef0e7
Generate TS getters
jgaehring Feb 20, 2024
158f939
Import IGetterOptions for all TS classes
jgaehring Feb 20, 2024
c0f156a
Omit async keyword from abstract methods
jgaehring Feb 20, 2024
37e388f
Fix getter return types for multiple primitives
jgaehring Feb 20, 2024
1242086
Generate TS setters
jgaehring Feb 20, 2024
a9cbc0a
Generate TS adders
jgaehring Feb 20, 2024
86b21cb
Provide stub for unimplemented remover methods
jgaehring Feb 20, 2024
cd6fa13
Fix primitive type names
jgaehring Feb 20, 2024
e1e8b6b
Fix getter's nullable result type
jgaehring Feb 20, 2024
d3771b0
Fix whitespace in getter template
jgaehring Feb 20, 2024
3b78232
Fix misaligned getter return types
jgaehring Feb 23, 2024
5be5e34
Sort & alphabetize TS factory imports
jgaehring Feb 22, 2024
234dbf2
Replace deprecated subs of ISKOSConcept in static
jgaehring Feb 23, 2024
989562a
Copy static test files from orig TS repo
jgaehring Feb 24, 2024
9066d98
Add auto import queries
lecoqlibre Feb 29, 2024
2797228
Generate TypeScript imports automatically
lecoqlibre Feb 29, 2024
060a46a
Prevent auto self importing
lecoqlibre Feb 29, 2024
bd3dafa
Fix return type of getImportedClasses
lecoqlibre Mar 2, 2024
7e26217
Add queries in changelog and docs in readme
lecoqlibre Mar 2, 2024
9e46ac4
Fix abstract sub classes should not re-implement methods already impl…
lecoqlibre Mar 8, 2024
b82362f
Add queries for operations to be implemented or declared by a class
lecoqlibre Mar 8, 2024
af75f05
TypeScript use queries to implement or declare operations in classes
lecoqlibre Mar 8, 2024
db31a38
Update context IRIs from static.dfc.org
jgaehring Mar 5, 2024
bbeaf87
Use Node's native test runner
jgaehring Mar 12, 2024
91af2d6
Remove Jest devDeps and config
jgaehring Mar 12, 2024
c840fe7
WIP: Remove unnecessary async keywords in tests
jgaehring Mar 12, 2024
849169b
Use Semantizer alpha.3
lecoqlibre Mar 13, 2024
ab368c6
Fix blank node, tests and features from previous ungenerated releases
lecoqlibre Mar 14, 2024
3ff8d8a
Fix mistaken expected json for some tests
lecoqlibre Mar 14, 2024
1eb5769
Add test for PlannedTransformationLoop, fix Connector
lecoqlibre Mar 15, 2024
84b7d1e
Update commit hash on semantizer in package-lock
jgaehring Mar 15, 2024
88f06af
Fix missing narrower and top concepts in vocabulary and product types
lecoqlibre Mar 18, 2024
c658552
Add transformation loop import test
lecoqlibre Mar 19, 2024
5e09194
Store objects in constructor
lecoqlibre Mar 20, 2024
8a81cca
Allow several consumption/production flows in PlannedTransformation
lecoqlibre Mar 20, 2024
31a4e51
Fix extra async and add DefinedProduct:image
lecoqlibre Mar 20, 2024
2c30e0f
Use factory to create objects, update Readme and Changelog
lecoqlibre Mar 21, 2024
1cb3083
Generate TS tests for concrete class constructors.
jgaehring Apr 1, 2024
50f48ee
Add type annotations to TS import/export methods
jgaehring Oct 30, 2024
e017314
Fix CHANGELOG.md
lecoqlibre Nov 18, 2024
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Queries for auto-importing (`getImportedClasses`, `getImportedInterfaces`, `getImportedClassifiers`, `getImportedClassifiersWithoutPrimitives` and `getImportedTypesOfOperations`).
- Queries for operations to be implemented or declared by a class:
- `getAllImplementedInterfacesWithoutParents`.
- `getOperationsToImplementOrDeclareFromInterfacesWithoutParents`.
- `getOperationsToImplementOrDeclare`.

## [1.1.0] - 2024-10-22

### Added
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ You will find predefined queries in the `queries.mtl` file contained in the `org
|`getAbstractClasses(model: Model): Bag(Class)`| Returns all the abstract classes of the model. |
|`getAdder(p: Parameter): Operation`| Returns the adder operation related to parameter. |
|`getAdder(p: Property): Operation`| Returns the adder operation related to the property. |
|`getAllImplementedInterfacesWithoutParents(Class): Set(Interface)`| Returns all the implemented interfaces of the class but without all the implemented interface of the parent class if any. |
|`getClasses(model: Model): Bag(Class)`| Returns all the classes of the model. |
|`getClassifiers(model: Model): Bag(NamedElement)`| Returns all the classes and interfaces of the model. |
|`getConcreateClasses(model: Model): Bag(Class)`| Returns all the concreate classes of the model. |
Expand All @@ -104,6 +105,15 @@ You will find predefined queries in the `queries.mtl` file contained in the `org
|`getImplementation(aType: Type, model: Model): Class`| Returns the class that implements the passed type. |
|`getImplementation(i: Interface, model: Model): Class`| Returns the (first-one) class that implements the passed interface. |
|`getImplementations(i: Interface, model: Model): Bag(Class)`| Returns the classes that implements the passed interface. |
|`getImportedClasses(aClass: Class): Set(Class)`| Computes the classes that the passed class needs to import. |
|`getImportedClasses(anInterface: Interface): Set(Class)`| Computes the classes that the passed interface needs to import. |
|`getImportedClassifiers(aClass: Class): Set(Classifier)`| Computes the classifiers (classes and interfaces) that the passed class needs to import. |
|`getImportedClassifiers(anInterface: Interface): Set(Classifier)`| Computes the classifiers (classes and interfaces) that the passed interface needs to import. |
|`getImportedClassifiers(c: Classifier): Set(Classifier)`| Computes the classifiers (classes and interfaces) that the passed classifier needs to import. |
|`getImportedClassifiersWithoutPrimitives(c: Classifier)`| Computes the classifiers (classes and interfaces) without primitives types (ex: String, Boolean, Integer) that the passed class needs to import. |
|`getImportedInterfaces(aClass: Class): Set(Interface)`| Computes the interfaces that the passed class needs to import. |
|`getImportedInterfaces(anInterface: Interface): Set(Interface)`| Computes the interfaces that the passed interface needs to import. |
|`getImportedTypesOfOperations(classifier: Classifier): Set(Type)`| Returns all the types of the parameters used by the operations (input parameters and output parameters) of the passed classifier. |
|`getInitializedParentParameters(operation: Operation): OrderedSet(Parameter)`| For a constructor, returns the parameters that have already been initialized by the parent constructor. |
|`getInitializerProperty(p: Parameter): Property`| Returns the property (class variable) that the parameter will initialize. |
|`getInitializerPropertyGetter(p: Parameter): Operation`| Returns the getter operation of the property (class variable) that the parameter will initialize. |
Expand All @@ -113,6 +123,8 @@ You will find predefined queries in the `queries.mtl` file contained in the `org
|`getInterfaces(model: Model): Bag(Interface)`| Returns all the interfaces of the model. |
|`getMapping(element: Element): String`| Returns the mapped URI of the element. For instance, if you call this query on the `Address` class, it should returns `dfc-b:Address`. |
|`getOperations(owner: Class): OrderedSet(Operation)`| Returns all the owned operations of the class. This won't return operations of inherited class or implemented interface(s). |
|`getOperationsToImplementOrDeclareFromInterfacesWithoutParents(Class): Bag(Operation)`| Returns the operations that need to be implemented from all the implemented interfaces of the class but without all the implemented interface of the parent class if any. |
|`getOperationsToImplementOrDeclare(Class): OrderedSet(Operation)`| Returns all the operation that the class need to implements. |
|`getPackageImports(model: Model): Set(PackageImport)`| Returns all the package imports of the model. |
|`getPackages(model: Model): Bag(Package)`| Returns all the packages imported by the model. |
|`getParameters(anOperation: Operation): OrderedSet(Parameter)`| Returns all the parameters of the operation. |
Expand Down
3 changes: 3 additions & 0 deletions default.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ php_outputFolder_test = php/test/
ruby_outputFolder_src = ruby/lib/datafoodconsortium/
ruby_outputFolder_test = ruby/test/

typescript_outputFolder_src = typescript/src/
typescript_outputFolder_test = typescript/test/

stereotypeAdder = datafoodconsortium_connector::adder
stereotypeBlankNode = datafoodconsortium_connector::blankNode
stereotypeConstructor = datafoodconsortium_connector::constructor
Expand Down
2 changes: 1 addition & 1 deletion src/org/datafoodconsortium/connector/codegen/Generate.java
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ public void registerResourceFactories(ResourceSet resourceSet) {
* @generated NOT
*/
public void copyStaticFiles() throws IOException {
String[] languages = new String[] { "php", "ruby" };
String[] languages = new String[] { "php", "ruby", "typescript" };

for (String language : languages) {
String base = "src/org/datafoodconsortium/connector/codegen/" + language;
Expand Down
2 changes: 2 additions & 0 deletions src/org/datafoodconsortium/connector/codegen/generate.mtl
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
[import org::datafoodconsortium::connector::codegen::queries /]
[import org::datafoodconsortium::connector::codegen::php::generate /]
[import org::datafoodconsortium::connector::codegen::ruby::generate /]
[import org::datafoodconsortium::connector::codegen::typescript::generate /]

[template public generate(model: Model)]
[comment @main /]
[initResources()/]
[generatePhp(model)/]
[generateRuby(model)/]
[generateTypeScript(model)/]
[/template]
13 changes: 13 additions & 0 deletions src/org/datafoodconsortium/connector/codegen/queries.mtl
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,30 @@
[query public getAbstractClasses(model: Model): Bag(Class) = model.getClasses()->select(c: Class | c.isAbstract) /]

[query public getInterfaces(model: Model): Bag(Interface) = model.getClassifiers()->selectByType(Interface) /]
[query public getAllImplementedInterfacesWithoutParents(aClass: Class): Set(Interface) = if (aClass.generalization->isEmpty()) then aClass.getAllImplementedInterfaces() else aClass.getAllImplementedInterfaces()->removeAll(aClass.generalization->asSequence()->at(1).general.oclAsType(Class).getAllImplementedInterfaces()) endif /]

[query public getImplementations(i: Interface, model: Model): Bag(Class) = model.getConcreateClasses()->select(c: Class | c.getAllImplementedInterfaces()->includes(i)) /]
[query public getImplementation(i: Interface, model: Model): Class = i.getImplementations(model)->asSequence()->at(1) /]
[query public getImplementation(aType: Type, model: Model): Class = if (aType.oclIsTypeOf(Interface)) then aType.oclAsType(Interface).getImplementation(model) else if (aType.oclIsTypeOf(Class)) then aType.oclAsType(Class) else null endif endif /]
[query public getImplementation(anElement: TypedElement, model: Model): Class = anElement.type.getImplementation(model) /]

[query public getImportedClasses(aClass: Class): Set(Class) = aClass.getImportedClassifiers()->filter(Class)->asSet() /]
[query public getImportedClasses(anInterface: Interface): Set(Class) = anInterface.getImportedClassifiers()->filter(Class)->asSet() /]
[query public getImportedInterfaces(aClass: Class): Set(Interface) = aClass.getImportedClassifiers()->filter(Interface)->asSet() /]
[query public getImportedInterfaces(anInterface: Interface): Set(Interface) = anInterface.getImportedClassifiers()->filter(Interface)->asSet() /]
[query public getImportedClassifiers(aClass: Class): Set(Classifier) = aClass.getGenerals()->union(aClass.interfaceRealization->collect(ir: InterfaceRealization | ir.contract)->asSet())->union(aClass.getImportedTypesOfOperations())->select(t: Type | aClass <> t) /]
[query public getImportedClassifiers(anInterface: Interface): Set(Classifier) = anInterface.getGenerals()->union(anInterface.getImportedTypesOfOperations())->select(t: Type | anInterface <> t) /]
[query public getImportedClassifiers(c: Classifier): Set(Classifier) = if (c.oclIsTypeOf(Interface)) then c.oclAsType(Interface).getImportedClassifiers() else c.oclAsType(Class).getImportedClassifiers() endif /]
[query public getImportedClassifiersWithoutPrimitives(c: Classifier): Set(Classifier) = c.getImportedClassifiers()->select(cl: Classifier | not cl.isPrimitive()) /]
[query public getImportedTypesOfOperations(classifier: Classifier): Set(Type) = self.getOperations()->collect(o: Operation | o.ownedParameter)->collect(p: Parameter | p.type)->asSet() /]

[query public hasGeneralization(classifier: Classifier): Boolean = not (classifier.generalization->isEmpty()) /]

[query public hasOwnedOperations(aClass: Class): Boolean = not aClass.ownedOperation->isEmpty() /]

[query public getOperations(owner: Class): OrderedSet(Operation) = owner.ownedOperation /]
[query public getOperationsToImplementOrDeclareFromInterfacesWithoutParents(aClass: Class): Bag(Operation) = aClass.getAllImplementedInterfacesWithoutParents()->collect(i: Interface | i.getOperations())->select(o: Operation | aClass.ownedOperation->excludesAll(aClass.ownedOperation->select(op: Operation | op.isAbstract and o.name = op.name))) /]
[query public getOperationsToImplementOrDeclare(owner: Class): OrderedSet(Operation) = if (owner.interfaceRealization->isEmpty()) then owner.getOperations() else owner.getOperations()->addAll(owner.getOperationsToImplementOrDeclareFromInterfacesWithoutParents()) endif /]

[query public getProperties(aClass: Class): OrderedSet(Property) = aClass.allAttributes() /]

Expand Down
35 changes: 35 additions & 0 deletions src/org/datafoodconsortium/connector/codegen/typescript/class.mtl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[comment encoding = UTF-8 /]
[module class('http://www.eclipse.org/uml2/5.0.0/UML')]

[import org::datafoodconsortium::connector::codegen::queries /]
[import org::datafoodconsortium::connector::codegen::typescript::common /]
[import org::datafoodconsortium::connector::codegen::typescript::operation /]

[template public generateClass(model: Model, aClass : Class)]
[file (getProperty('typescript_outputFolder_src') + aClass.name.concat('.ts'), false, 'UTF-8')]
[generateLicense()/]
[generateImports(aClass) /]
import IConnector from "./IConnector.js";
import IGetterOptions from "./IGetterOptions.js";

[if (not aClass.isAbstract)]
const [toSemanticTypeConst(aClass)/]: string = "[aClass.getValue(aClass.getAppliedStereotype('datafoodconsortium_connector::semantic'), 'map')/]";['\n'/]
[/if]
export default [if (aClass.isAbstract)]abstract [/if]class [aClass.name.toUpperFirst()/] [generateGeneralization(aClass)/][generateInterfaceRealizationHeader(aClass)/]{['\n'/]
[if (aClass.generalization->isEmpty())]
protected connector: IConnector;['\n'/]
[/if]
[for (operation: Operation | aClass.getOperationsToImplementOrDeclare()) separator('\n')]
[if (operation.isAbstract)][generateOperationSignature(aClass, operation)/][else][generateOperationImplementation(aClass, operation)/][/if]
[/for]
}
[/file]
[/template]

[template public generateGeneralization(classifier: Classifier)]
extends [for (generalization: Generalization | classifier.generalization) separator(', ')][generalization.general.name/][/for][if (classifier.generalization->isEmpty())][if (classifier.isSemantic())]SemanticObject[if (classifier.isBlankNode())]Anonymous[/if][/if][/if]
[/template]

[template public generateInterfaceRealizationHeader(aClass: Class)]
[if not (aClass.interfaceRealization->isEmpty())]implements [for (interface: InterfaceRealization | aClass.interfaceRealization) separator(', ')][interface.contract.name/][/for] [/if]
[/template]
31 changes: 31 additions & 0 deletions src/org/datafoodconsortium/connector/codegen/typescript/common.mtl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[comment encoding = UTF-8 /]
[module common('http://www.eclipse.org/uml2/5.0.0/UML')]

[import org::datafoodconsortium::connector::codegen::queries /]
[import org::datafoodconsortium::connector::codegen::php::common /]

[template public generateLicense(traceabilityContext: OclAny)][generateLicence()/][/template]

[template public generateImports(classifier: Classifier)]
[for (c: Classifier | classifier.getImportedClassifiersWithoutPrimitives()) separator('\n')][generateImport(c)/][/for]
[if (classifier.oclIsTypeOf(Class))]import { SemanticObject[if (classifier.isBlankNode())]Anonymous[/if] } from "@virtual-assembly/semantizer"[/if]
import { Semanticable } from "@virtual-assembly/semantizer"
[/template]

[template public generateTestImports(class: Class, model: Model) post(trim())]
[for (c: Classifier | class.getImportedClassifiersWithoutPrimitives())]
[let imp : Class = c.getImplementation(model)]
import [imp.name/] from "../../lib/[imp.name/].js"
[/let]
[/for]
[/template]

[template public generateImport(c: Classifier)]
import [c.name/] from "./[c.name/].js"
[/template]

[template public toSemanticTypeConst(classifier: Classifier) post(trim())]
[classifier.name.replaceAll('(.)([A-Z]+)', '$1_$2').toUpper()/]_SEM_TYPE
[/template]

[query public isAsyncParameter(p: Parameter): Boolean = ((p.upper = -1 and not p.type.isPrimitive()) or (not p.type.isBlankNode() and not p.type.isPrimitive())) /]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[comment encoding = UTF-8 /]
[module generate('http://www.eclipse.org/uml2/5.0.0/UML')/]

[import org::datafoodconsortium::connector::codegen::queries /]
[import org::datafoodconsortium::connector::codegen::typescript::class /]
[import org::datafoodconsortium::connector::codegen::typescript::interface /]
[import org::datafoodconsortium::connector::codegen::typescript::test /]

[template public generateTypeScript(model: Model)]
[for (aClass: Class | model.getClasses())][generateClass(model, aClass)/][/for]

[for (anInterface: Interface | model.getInterfaces())][generateInterface(anInterface)/][/for]

[for (aClass: Class | model.getConcreateClasses())][generateClassTest(model, aClass)/][/for]

[comment TODO: write factory generator][model.generateFactory()/][/comment]
[/template]
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[comment encoding = UTF-8 /]
[module interface('http://www.eclipse.org/uml2/5.0.0/UML')]

[import org::datafoodconsortium::connector::codegen::queries /]
[import org::datafoodconsortium::connector::codegen::typescript::common /]
[import org::datafoodconsortium::connector::codegen::typescript::operation /]

[template public generateInterface(anInterface : Interface)]
[file (getProperty('typescript_outputFolder_src') + anInterface.name.concat('.ts'), false, 'UTF-8')]
[generateLicense()/]
[generateImports(anInterface) /]

export default interface [anInterface.name.toUpperFirst()/] [generateGeneralization(anInterface)/]{

[for (operation: Operation | anInterface.ownedOperation) separator('\n')]
[generateComments(operation)/][generateOperationSignature(operation)/];
[/for]

}
[/file]
[/template]

[template public generateGeneralization(interface: Interface)]
[if (not (interface.generalization->isEmpty()) or interface.isSemantic())]extends [if (interface.isSemantic())]Semanticable[if (not (interface.generalization->isEmpty()))], [/if][/if][for (generalization: Generalization | interface.generalization) separator(', ') after(' ')][generalization.general.name/][/for][/if]
[/template]

[template public generateComments(operation: Operation) post(trim())]
[if (not operation.ownedComment->isEmpty())][for (c: Comment | operation.ownedComment) separator('\n') after('\n')]/* [c._body/] */[/for][/if]
[/template]

[template public generateOperationSignature(operation: Operation) post(trim())][operation.name/]([genOperationParameters(operation)/])[if not (operation.isConstructor())]: [generateOperationReturnType(operation)/][/if][/template]


[comment][template public generateOperationSignatureTypeScript(operation: Operation)][operation.name/]([genOperationParameters(operation)/])[if not (operation.isConstructor())]: [generateOperationReturnType(operation)/][/if][/template][/comment]
Loading