Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
fearthecowboy committed Mar 23, 2018
1 parent b2b5463 commit 446663f
Show file tree
Hide file tree
Showing 45 changed files with 958 additions and 238 deletions.
10 changes: 10 additions & 0 deletions common/text-manipulation.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Dictionary } from "#remodeler/common";

let indentation = " ";

Expand Down Expand Up @@ -112,6 +113,15 @@ export function fixEOL(content: string) {
return content.replace(/\r\n/g, EOL);
}

export function map<T, U>(dictionary: Dictionary<T>, callbackfn: (key: string, value: T) => U, thisArg?: any): U[] {
return Object.getOwnPropertyNames(dictionary).map((key) => callbackfn(key, dictionary[key]));
}
export function selectMany<T>(multiArray: T[][]): T[] {
const result = new Array<T>();
multiArray.map(v => result.push(...v));
return result;
}

export function indent(content: string, factor: number = 1): string {
const i = indentation.repeat(factor);
content = i + fixEOL(content.trim());
Expand Down
1 change: 1 addition & 0 deletions csharp/code-dom/access-modifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export enum AccessModifier {
ProtectedInternal = "protected internal",
PrivateProtected = "private protected",
Private = "private",
Default = "",
}

const order = [AccessModifier.Public, AccessModifier.Internal, AccessModifier.Protected, AccessModifier.ProtectedInternal, AccessModifier.PrivateProtected, AccessModifier.Private];
Expand Down
6 changes: 5 additions & 1 deletion csharp/code-dom/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { Namespace } from "./namespace";

export class Class extends Type {
protected classOrStruct: "class" | "struct" = "class";
public isStatic: boolean = false;

protected fields = new Array<Field>();
public partial: boolean = false;

Expand All @@ -25,9 +27,11 @@ export class Class extends Type {
const implementsInterfaces = this.interfaces.map(v => v.fullName).join(', ');
const description = comment(this.description, docCommentPrefix);
const partial = this.partial ? "partial " : "";
const stat = this.isStatic ? "static " : "";

return `
${description}
${this.accessModifier} ${partial}${this.classOrStruct} ${this.name}${colon}${extendsClass}${comma}${implementsInterfaces}
${this.accessModifier} ${stat}${partial}${this.classOrStruct} ${this.name}${colon}${extendsClass}${comma}${implementsInterfaces}
`.trim();
}

Expand Down
6 changes: 3 additions & 3 deletions csharp/code-dom/initializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ export class Initializer {
protected apply<T>(initializer?: Partial<T>) {
if (initializer) {
for (const i in (<any>initializer)) {
if ((<any>initializer)[i]) {
(<any>this)[i] = (<any>initializer)[i]
};
//if ((<any>initializer)[i]) {
(<any>this)[i] = (<any>initializer)[i]
//};
}
}
}
Expand Down
25 changes: 25 additions & 0 deletions csharp/code-dom/method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,29 @@ ${indent(super.implementation)}
}`.trim();

}
}

export class PartialMethod extends Method {
constructor(name: string, returnType: TypeDeclaration = mscorlib.Void, objectIntializer?: Partial<PartialMethod>) {
super(name, returnType);
this.apply(objectIntializer);
}

public get declaration(): string {
const parameterDeclaration = this.parameters.joinWith(p => p.declaration, CommaChar);
const stat = this.isStatic ? "static " : "";
const asynch = this.isAsync ? "async " : "";
return `
${this.summaryDocumentation}
${this.parameterDocumentation}
partial ${stat}${asynch}${this.returnType.use} ${this.name}(${parameterDeclaration})
`.trim();
}

public get implementation(): string {
return `
${this.declaration};`.trim();

}

}
7 changes: 1 addition & 6 deletions csharp/code-dom/mscorlib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ export class LibraryType implements TypeDeclaration {
return `${this.fullName}`;
}

public validation(propertyName: string): string {
return '';
}

public get implementation(): string {
return ``;
}
Expand All @@ -30,8 +26,7 @@ export const Duration: TypeDeclaration = new LibraryType("TimeSpan");
export const Binary: TypeDeclaration = new LibraryType("byte[]");
export const Bool: TypeDeclaration = new LibraryType("bool");
export const Object: TypeDeclaration = new LibraryType("object");

export const ThisObject: TypeDeclaration = new LibraryType("this object");

export const Task: TypeDeclaration = new LibraryType("System.Threading.Tasks.Task");
export const CancellationToken: TypeDeclaration = new LibraryType("System.Threading.CancellationToken");
export const EventListener: TypeDeclaration = new LibraryType("Microsoft.Rest.EventListener");
6 changes: 6 additions & 0 deletions csharp/code-dom/parameter-modifier.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum ParameterModifier {
None = "",
Ref = "ref",
Out = "out",
In = "in",
}
9 changes: 7 additions & 2 deletions csharp/code-dom/parameter.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { TypeDeclaration } from "./type-declaration";
import { Expression } from "#csharp/code-dom/expression";
import { Initializer } from "#csharp/code-dom/initializer";
import { ParameterModifier } from "#csharp/code-dom/parameter-modifier";

export class Parameter extends Initializer implements Expression {
public description: string = "";
public genericParameters = new Array<string>();
public where?: string;
public modifier: ParameterModifier = ParameterModifier.None;
public defaultInitializer?: string;

public constructor(private name: string, private type: TypeDeclaration, public genericParameters = new Array<string>(), public where?: string, objectInitializer?: Partial<Parameter>) {
public constructor(public name: string, public type: TypeDeclaration, objectInitializer?: Partial<Parameter>) {
super();
this.apply(objectInitializer);
}
Expand All @@ -14,7 +19,7 @@ export class Parameter extends Initializer implements Expression {
return `<param name="${this.name}"> ${this.description} </param>`;
}
public get declaration(): string {
return `${this.type.use} ${this.name}`;
return `${this.modifier} ${this.type.use} ${this.name} ${this.defaultInitializer || ''}`.trim();
}
public get use(): string {
return this.name;
Expand Down
41 changes: 38 additions & 3 deletions csharp/code-dom/statements/statement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { LiteralStatement } from "#csharp/code-dom/statements/literal";
import { Initializer } from "../initializer";

export type OneOrMoreStatements = string | (() => Iterable<string | Statement>) | Iterable<string | Statement> | Statement;
export type ManyStatements = OneOrMoreStatements | (() => Iterable<OneOrMoreStatements>);

export interface Statement {
implementation: string;
Expand All @@ -22,11 +23,21 @@ export class Statements extends Initializer implements Statement {
this.apply(objectIntializer);
}

public add(statements: OneOrMoreStatements): Statements {
public get count(): number {
return this.statements.length
}

public add(statements: ManyStatements): Statements {
if (typeof statements === 'function') {
statements = statements();
// console.error(statements);
for (const each of statements()) {
this.aadd(each);
}
//statements = statements();
return this;
}
if (typeof statements === 'string') {
return this.aadd(statements);
/*if (typeof statements === 'string') {
statements = new LiteralStatement(statements);
}
if (typeof statements === 'object') {
Expand All @@ -38,6 +49,30 @@ export class Statements extends Initializer implements Statement {
}
}
}
return this;*/
}
private aadd(statements: OneOrMoreStatements): Statements {
if (typeof statements === 'function') {
console.error(statements);
statements = statements();
}
if (typeof statements === 'string') {
this.statements.push(new LiteralStatement(statements));
return this;
}
if (typeof statements === 'object') {
console.error(statements);
if (isStatement(statements)) {
this.statements.push(statements);
} else if (statements instanceof Statements) {
this.statements.push(...statements.statements)
}
else {
for (const statement of statements) {
this.statements.push(typeof statement === 'string' ? new LiteralStatement(statement) : statement);
}
}
}
return this;
}

Expand Down
1 change: 0 additions & 1 deletion csharp/code-dom/type-declaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@
export interface TypeDeclaration {
implementation: string;
use: string;
validation(propertyName: string): string;
}
1 change: 0 additions & 1 deletion csharp/inferrer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { deserialize, serialize } from "#common/yaml";
import { processCodeModel } from "#common/process-code-model";
import { ModelState } from "#common/model-state";
import { Model } from "remodeler/code-model";
import { deconstruct, fixLeadingNumber, pascalCase, camelCase } from "#common/text-manipulation";

export async function process(service: Host) {
return await processCodeModel(inferStuff, service);
Expand Down
15 changes: 14 additions & 1 deletion csharp/lowlevel-generator/clientruntime.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
import { TypeDeclaration } from "#csharp/code-dom/type-declaration";
import { LibraryType } from "#csharp/code-dom/mscorlib";
import { Namespace } from "#csharp/code-dom/namespace";
import { Interface } from "#csharp/code-dom/interface";

export const ClientRuntime: Namespace = new Namespace("Microsoft.Rest.ClientRuntime");

export const ISendAsync: Interface = new Interface(ClientRuntime, "ISendAsync");
export const IJsonSerializable: Interface = new Interface(ClientRuntime, "IJsonSerializable");
export const IXmlSerializable: Interface = new Interface(ClientRuntime, "IXmlSerializable");

export const EventListener: TypeDeclaration = new LibraryType(`${ClientRuntime.fullName}.EventListener`);
export const IValidates: Interface = new Interface(ClientRuntime, "IValidates");

export const JsonNode: TypeDeclaration = new LibraryType(`Carbon.Json.JsonNode`);
export const JsonObject: TypeDeclaration = new LibraryType(`Carbon.Json.JsonObject`);

export const ISendAsync: TypeDeclaration = new LibraryType("Microsoft.Rest.ISendAsync");
5 changes: 0 additions & 5 deletions csharp/lowlevel-generator/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ import { Model, Schema } from "remodeler/code-model";
import { TypeDeclaration } from "#csharp/code-dom/type-declaration";
import { Project } from "./project";


export interface PrivateData {

}

export class State extends ModelState<Model> {

public get project(): Project {
Expand Down
3 changes: 1 addition & 2 deletions csharp/lowlevel-generator/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { deserialize } from "#common/yaml";

// model constructors?
// - allOf creation?
// enum generator

// validations
// serialization/deserialization/polymorphic deserializer/shape deserializer?
// url construction
Expand All @@ -29,7 +29,6 @@ import { deserialize } from "#common/yaml";

// client runtime

// later: refactor create/async to be consistent

export async function process(service: Host) {
try {
Expand Down
65 changes: 60 additions & 5 deletions csharp/lowlevel-generator/model/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,35 @@ import { Interface } from "#csharp/code-dom/interface";
import { ProxyProperty } from "./proxy-property";
import { Field } from "#csharp/code-dom/field";
import { AccessModifier } from "#csharp/code-dom/access-modifier";
import { IJsonSerializable, EventListener, IValidates } from "#csharp/lowlevel-generator/clientruntime";
import { Statements, OneOrMoreStatements } from "#csharp/code-dom/statements/statement";
import { PrivateData } from "#csharp/lowlevel-generator/private-data";
import { EOL } from "#common/text-manipulation";
import { Method } from "#csharp/code-dom/method";
import { Parameter } from "#csharp/code-dom/parameter";

export class ModelClass extends Class {

public serializeStatements = new Statements();
private validateMethod?: Method;

constructor(namespace: Namespace, schema: Schema, state: State, objectInitializer?: Partial<ModelClass>) {
super(namespace, schema.details.name);
this.apply(objectInitializer);

const privateData: PrivateData = schema.details.privateData;

// mark the code-model with the class we're creating.
schema.details.privateData["class-implementation"] = this;
privateData.classImplementation = this;

// track the namespace we've used.
schema.details.namespace = namespace.fullName;

// mark it as json serializable
this.interfaces.push(IJsonSerializable);

// create an interface for this model class
const modelInterface = schema.details.privateData["interface-implementation"] || new ModelInterface(namespace, schema, state);
const modelInterface = privateData.interfaceImplementation || new ModelInterface(namespace, schema, this, state);
this.interfaces.push(modelInterface);

// handle <allOf>s
Expand All @@ -35,10 +49,10 @@ export class ModelClass extends Class {
const aSchema = schema.allOf[allOf];
const aState = state.path("allOf");

const td = state.project.modelsNamespace.resolveTypeDeclaration(aSchema, aState);
const td = state.project.modelsNamespace.resolveTypeDeclaration(aSchema, true, aState);

// add the interface as a parent to our interface.
const iface: ModelInterface = aSchema.details.privateData["interface-implementation"];
const iface: ModelInterface = aSchema.details.privateData.interfaceImplementation;

modelInterface.interfaces.push(iface);

Expand All @@ -47,6 +61,8 @@ export class ModelClass extends Class {

// now, create proxy properties for the members
iface.allProperties.map(each => this.addProperty(new ProxyProperty(backingField, each, state)));

this.serializeStatements.add(`${backingField.value}?.ToJson(result);`)
}
// generate a protected backing field for each
// and then expand the nested properties into this class forwarding to the member.
Expand All @@ -56,7 +72,9 @@ export class ModelClass extends Class {
for (const propertyName in schema.properties) {
const property = schema.properties[propertyName];

this.addProperty(new ModelProperty(this, property, state.path('properties', propertyName)));
const prop = this.addProperty(new ModelProperty(this, property, state.path('properties', propertyName)));

this.serializeStatements.add(`result.Add("${propertyName}",${prop.name}.ToJson());`);
}

if (schema.additionalProperties) {
Expand All @@ -69,6 +87,43 @@ export class ModelClass extends Class {
}
}

// add validation function
const statements = new Statements();
this.properties.map(each => statements.add((<ModelProperty>each).validatePresenceStatement));
this.properties.map(each => statements.add((<ModelProperty>each).validationStatement));

// const propVal = this.properties.joinWith(each => (<ModelProperty>each).validationStatement, EOL);
// const propValPresence = this.properties.joinWith(each => (<ModelProperty>each).validatePresenceStatement, EOL);

if (statements.count > 0) {
// we do have something to valdiate!

// add the IValidates implementation to this object.
this.interfaces.push(IValidates);
this.validateMethod = this.addMethod(new Method("Validate", mscorlib.Task, {
parameters: [new Parameter("listener", EventListener)],
isAsync: true,
}));
this.validateMethod.add(statements);
}

}

validatePresence(propertyName: string): OneOrMoreStatements {
return `await listener.AssertNotNull(nameof(${propertyName}),${propertyName});`.trim();
}

validateValue(propertyName: string): OneOrMoreStatements {
//if (this.validateMethod) {
//return `${propertyName}.Validate(listener);`
//}
// return `(${propertyName} as Microsoft.Rest.ClientRuntime.IValidates)?.Validate(listener);`;
return `await listener.AssertObjectIsValid(nameof(${propertyName}), ${propertyName});`;
}
jsonserialize(propertyName: string): OneOrMoreStatements {
return `/* serialize json object here */`;
}
jsondeserialize(propertyName: string): OneOrMoreStatements {
return `/* deserialize json object here */`;
}
}
Loading

0 comments on commit 446663f

Please sign in to comment.