mean-expert-official / loopback-sdk-builder

Tool for auto-generating Software Development Kits (SDKs) for LoopBack
Other
399 stars 177 forks source link

RC.2 breaking #46

Closed cyberbobjr closed 8 years ago

cyberbobjr commented 8 years ago

Hi, I test the new rc2 sdk builder, but i have some bugs :(

First of all, i launch the build:sdk command, everything is ok, but when i launch the typescript compiler, i have these errors :

Error:(20, 1) TS2308: Module './AccessToken' has already exported a member named 'AccessToken'. Consider explicitly re-exporting to resolve the ambiguity.

this is the content of my sdk/models/index.ts :

/* tslint:disable */
export * from './AccessToken';

export * from './Seminaire';

export * from './User';

export * from './UserEvent';

export * from './UserSeminaire';

export * from './Session';

export * from './Feed';

export * from './Like';

export * from './Comment';

export * from './UserSession';

export * from './Intervenant';

export * from './Image';

export * from './Organisateur';

export * from './Notation';

export * from './ACL';

export * from './RoleMapping';

export * from './Role';

export * from './Email';

export * from './BaseModels';

the error come from the last line because a conflict exist with /AccessToken.

Content of sdk/models/AccessToken.ts :

/* tslint:disable */
import {
    User
} from '../index';

export interface AccessTokenInterface {
    id?:string;
    /**
     * time to live in seconds (2 weeks by default)
     */
    ttl?:number;
    created?:any;
    userId?:string;
    user?:User;
}

export class AccessToken implements AccessTokenInterface {
    id:string;
    /**
     * time to live in seconds (2 weeks by default)
     */
    ttl:number;
    created:any;
    userId:string;
    user:User;

    constructor(instance?:AccessToken) {
        Object.assign(this, instance);
    }
}

Content of sdk/models/BaseModels.ts :

/* tslint:disable */
export interface LoopBackFilterInterface {
  fields?: any;
  include?: any;
  limit?: any;
  order?: any;
  skip?: any;
  offset?: any;
  where?: any;
}

export class LoopBackFilter implements LoopBackFilterInterface {
  fields: any;
  include: any;
  limit: any;
  order: any;
  skip: any;
  offset: any;
  where: any;
}

export interface TokenInterface {
  id?: any;
  user?: any;
  userId?: any;
  ttl?: any;
  created?: any;
}

export class AccessToken implements TokenInterface {
  id: any;
  user: any;
  userId: any;
  ttl: any;
  created: any;
}

This is the 1st error, if i rename AccessToken to Token inside BaseModels.ts, my console.log display this error after the application launching :

zone.js:323 Error: (SystemJS) TypeError: Class extends value undefined is not a function or null at Object.eval (http://localhost:3000/sdk/services/custom/AccessToken.js:27:58) at eval (http://localhost:3000/sdk/services/custom/AccessToken.js:948:4) at eval (http://localhost:3000/sdk/services/custom/AccessToken.js:949:3) at Object.eval (http://localhost:3000/sdk/services/custom/index.js:6:10) Evaluating http://localhost:3000/sdk/services/custom/AccessToken.js Evaluating http://localhost:3000/sdk/services/custom/index.js Evaluating http://localhost:3000/sdk/services/index.js Evaluating http://localhost:3000/sdk/index.js Evaluating http://localhost:3000/sdk/services/core/logger.service.js Evaluating http://localhost:3000/sdk/services/core/index.js Evaluating http://localhost:3000/sdk/services/custom/Organisateur.js Evaluating http://localhost:3000/services/auth.service.js Evaluating http://localhost:3000/app/ui/navbar.component.js Evaluating http://localhost:3000/app/app.component.js Evaluating http://localhost:3000/app/main.js Error loading http://localhost:3000/app/main.js

I don't understand what is the problem... please do you have this bug ? and can you resolve it please ?

Many thanks for your help, best regards BM

jonathan-casarrubias commented 8 years ago

@cyberbobjr I see where the issue is

By default loopback sets the AccessToken model as private in server/model-config.json, I have been working all this time with the assumption that it will remain private.

And that is the reason I created a declaration in BaseModels, I think what I need to do here is to validate if the AccessToken is public -like you are doing- I will not add it in base models.

Thanks for reporting

Cheers!!

cyberbobjr commented 8 years ago

Hi Jonathan, Many thanks for your answer, i've put the AccessToken in private, and rebuild the Angular2 SDK with the last version of the builder (rc3.2) but i've still have a bug in the console :(

zone.js:323 Error: (SystemJS) TypeError: Class extends value undefined is not a function or null at Object.eval (http://localhost:3000/sdk/services/custom/Seminaire.js:27:54) at eval (http://localhost:3000/sdk/services/custom/Seminaire.js:1528:4) at eval (http://localhost:3000/sdk/services/custom/Seminaire.js:1529:3) at Object.eval (http://localhost:3000/sdk/services/custom/index.js:6:10) Evaluating http://localhost:3000/sdk/services/custom/Seminaire.js Evaluating http://localhost:3000/sdk/services/custom/index.js Evaluating http://localhost:3000/sdk/services/index.js Evaluating http://localhost:3000/sdk/index.js Evaluating http://localhost:3000/sdk/services/core/logger.service.js Evaluating http://localhost:3000/sdk/services/core/index.js Evaluating http://localhost:3000/sdk/services/custom/Organisateur.js Evaluating http://localhost:3000/services/auth.service.js Evaluating http://localhost:3000/app/ui/navbar.component.js Evaluating http://localhost:3000/app/app.component.js Evaluating http://localhost:3000/app/main.js Error loading http://localhost:3000/app/main.js

this is my tsconfig.json :

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules",
    "typings",
    "typings/browser.d.ts"
  ]
}

this is the description of the seminaire model :

{
  "name": "Seminaire",
  "plural": "Seminaires",
  "base": "PersistedModel",
  "idInjection": true,
  "options": {
    "validateUpsert": true
  },
  "properties": {
    "id": {
      "type": "string",
      "required": true
    },
    "title": {
      "type": "string",
      "required": true
    },
    "details": {
      "type": "string"
    },
    "startDateTime": {
      "type": "string",
      "required": true
    },
    "endDateTime": {
      "type": "string",
      "required": true
    },
    "locationLong": {
      "type": "string"
    },
    "locationLat": {
      "type": "string"
    },
    "pathPicture": {
      "type": "string"
    },
    "address": {
      "type": "object"
    },
    "public": {
      "type": "boolean",
      "required": true
    },
    "category": {
      "type": "string"
    }
  },
  "validations": [],
  "relations": {
    "users": {
      "type": "hasMany",
      "model": "UserEvent",
      "foreignKey": "seminaireId",
      "through": "UserSeminaire",
      "keyThrough": "userId"
    },
    "intervenants": {
      "type": "hasMany",
      "model": "Intervenant"
    },
    "sessions": {
      "type": "hasMany",
      "model": "Session",
      "foreignKey": "seminaireId"
    },
    "feeds": {
      "type": "hasMany",
      "model": "Feed",
      "foreignKey": "seminaireId"
    },
    "organisateur": {
      "type": "belongsTo",
      "model": "Organisateur"
    }
  },
  "acls": [
    {
      "accessType": "*",
      "principalType": "ROLE",
      "principalId": "$everyone",
      "permission": "DENY"
    },
    {
      "accessType": "*",
      "principalType": "ROLE",
      "principalId": "$authenticated",
      "permission": "ALLOW"
    }
  ],
  "methods": {}
}

I disabled the Seminaire model, but the same error come for the other models (users, etc.) I use the latest Angular2 engine (rc.4)

I'll try on a empty project for testing but it's really strange :(

cyberbobjr commented 8 years ago

Some progress : if i remove this line in main.ts :

import {API_PROVIDERS} from "../sdk";

and replace by :

import {LoopBackAuth} from "../sdk/services/core/auth.service";
import {JSONSearchParams} from "../sdk/services/core/search.params";

AND if in the generated /sdk/services/custom/Seminaire.ts i replace this :

import {LoopBackAuth, ErrorHandler, JSONSearchParams,BaseLoopBackApi} from "../core/index";

by this :

import {LoopBackAuth, ErrorHandler, JSONSearchParams} from "../core/index";
import {BaseLoopBackApi} from "../core/base.service";

all is working. I suspect some "magic search path bug" inside the generated JS /sdk/services/custom/Seminaire.js :

System.register(["@angular/core", "@angular/http", "../core/index", "../core/base.service", "../../models/index", "../../lb.config", "rxjs/add/observable/throw", "rxjs/add/operator/map", "rxjs/add/operator/catch", "rxjs/add/operator/share"], function(exports_1, context_1) {

if i let the "../core/index" alone, the app crash, if i add "../core/base.service" in the System.register(), the app running. It's look like System.register doesn't import all the files...

I know how to resolve it (import manually one by one the core service & custom models), but i don't know why !?!?

jonathan-casarrubias commented 8 years ago

@cyberbobjr are you using angular-cli?

The very first issue regarding private models remains and I need to fix it, there is another issue already related to this, I hope to deliver the fix ASAP.

But the second issue you have, is different.

Im using system.js (angular-cli) and the only configuration I need it to make it work is to add in system-config.ts the following:

const barrels: string[] = [
  // Angular specific barrels.
  '@angular/core',
  '@angular/common',
  '@angular/compiler',
  '@angular/forms',
  '@angular/http',
  '@angular/router',
  '@angular/platform-browser',
  '@angular/platform-browser-dynamic',

  // Thirdparty barrels.
  'rxjs',

  // App specific barrels.
  'app',
  'app/shared',
  .....
  /** @cli-barrel */
];

As you can see I only add app/shared then in shared/index.ts I export the sdk as follows:

export * from './sdk/index'; // index word is important

I have detected an issue when not using the index, It should automatically take the index file if you don't explicitly define it, but looks like when there are many nested modules, that functionality does not always work

So please make sure you don't export the sdk using only

export * from './sdk';

I had that issue in the past and I'm trying to add the index word in every export and import statement.

I hope this helps you fix the linking modules issue.

Cheers Jon

cyberbobjr commented 8 years ago

Hi Jonathan, thanks you for your answer, i use the systems.config.js like the quickstart of Angular2, this is my systemjs.config.js :

(function (global) {

    // map tells the System loader where to look for things
    var map = {
        'app': 'app', // 'dist',
        'rxjs': 'node_modules/rxjs',
        'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
        '@angular': 'node_modules/@angular',
        'services': 'services',
        'shared': 'shared',
        'models': 'models',
        'sdk': 'sdk',
        'ng2-bootstrap': 'node_modules/ng2-bootstrap',
        'moment': 'node_modules/moment/moment.js',
        'angular2-jwt': 'node_modules/angular2-jwt',
        "ng2-dragula": "node_modules/ng2-dragula",
        "dragula": "node_modules/dragula",
        'angular2-cookie': 'node_modules/angular2-cookie',
        'angular2-moment': 'node_modules/angular2-moment',
        'angular2-notifications': 'node_modules/angular2-notifications',
        "symbol-observable": "node_modules/symbol-observable"
    };

    // packages tells the System loader how to load when no filename and/or no extension
    var packages = {
        'app': {main: 'main.js', defaultExtension: 'js'},
        'moment': {
            defaultExtension: 'js'
        },
        'angular2-moment': {
            main: 'index.js',
            defaultExtension: 'js'
        },
        'rxjs': {defaultExtension: 'js'},
        'ng2-bootstrap': {main: 'ng2-bootstrap.js', defaultExtension: 'js'},
        'sdk': {main: 'index.js', defaultExtension: 'js'},
        'angular2-jwt': {defaultExtension: 'js'},
        'angular2-in-memory-web-api': {defaultExtension: 'js'},
        "services": {
            defaultExtension: 'js'
        },
        "models": {
            defaultExtension: 'js'
        },
        "ng2-dragula": {
            defaultExtension: "js"
        },
        'angular2-notifications': {main: 'components.js', defaultExtension: 'js'},
        "dragula": {
            main: "dist/dragula",
            defaultExtension: "js"
        },
        'angular2-cookie': {main: 'core.js', defaultExtension: 'js'},
        "symbol-observable": {"defaultExtension": "js", main: "index.js"}
    };

    var packageNames = [
        '@angular/common',
        '@angular/compiler',
        '@angular/core',
        '@angular/http',
        '@angular/forms',
        '@angular/platform-browser',
        '@angular/platform-browser-dynamic',
        '@angular/router',
        '@angular/testing',
        '@angular/upgrade'
    ];

    // add package entries for angular packages in the form '@angular/common': { main: 'index.js', defaultExtension: 'js' }
    packageNames.forEach(function (pkgName) {
        packages[pkgName] = {main: 'index.js', defaultExtension: 'js'};
    });

    var config = {
        map: map,
        packages: packages
    };

    // filterSystemConfig - index.html's chance to modify config before we register it.
    if (global.filterSystemConfig) {
        global.filterSystemConfig(config);
    }
    ;

    System.config(config);

})(this);

Do you think my systemjs file is wrong ?

Thanks you, best regards

jonathan-casarrubias commented 8 years ago

@cyberbobjr can you try this

(function (global) {

    // map tells the System loader where to look for things
    var map = {
        'app': 'app', // 'dist',
        'rxjs': 'node_modules/rxjs',
        'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
        '@angular': 'node_modules/@angular',
        'ng2-bootstrap': 'node_modules/ng2-bootstrap',
        'moment': 'node_modules/moment/moment.js',
        'angular2-jwt': 'node_modules/angular2-jwt',
        "ng2-dragula": "node_modules/ng2-dragula",
        "dragula": "node_modules/dragula",
        'angular2-cookie': 'node_modules/angular2-cookie',
        'angular2-moment': 'node_modules/angular2-moment',
        'angular2-notifications': 'node_modules/angular2-notifications',
        "symbol-observable": "node_modules/symbol-observable"
    };

    // packages tells the System loader how to load when no filename and/or no extension
    var packages = {
        'app': {main: 'main.js', defaultExtension: 'js'},
        'app/shared': { main: 'index' },
        'moment': {
            defaultExtension: 'js'
        },
        'angular2-moment': {
            main: 'index.js',
            defaultExtension: 'js'
        },
        'rxjs': {defaultExtension: 'js'},
        'ng2-bootstrap': {main: 'ng2-bootstrap.js', defaultExtension: 'js'},
        'sdk': {main: 'index.js', defaultExtension: 'js'},
        'angular2-jwt': {defaultExtension: 'js'},
        'angular2-in-memory-web-api': {defaultExtension: 'js'},
        "ng2-dragula": {
            defaultExtension: "js"
        },
        'angular2-notifications': {main: 'components.js', defaultExtension: 'js'},
        "dragula": {
            main: "dist/dragula",
            defaultExtension: "js"
        },
        'angular2-cookie': {main: 'core.js', defaultExtension: 'js'},
        "symbol-observable": {"defaultExtension": "js", main: "index.js"}
    };

    var packageNames = [
        '@angular/common',
        '@angular/compiler',
        '@angular/core',
        '@angular/http',
        '@angular/forms',
        '@angular/platform-browser',
        '@angular/platform-browser-dynamic',
        '@angular/router',
        '@angular/testing',
        '@angular/upgrade'
    ];

    // add package entries for angular packages in the form '@angular/common': { main: 'index.js', defaultExtension: 'js' }
    packageNames.forEach(function (pkgName) {
        packages[pkgName] = {main: 'index.js', defaultExtension: 'js'};
    });

    var config = {
        map: map,
        packages: packages
    };

    // filterSystemConfig - index.html's chance to modify config before we register it.
    if (global.filterSystemConfig) {
        global.filterSystemConfig(config);
    }
    ;

    System.config(config);

})(this);
cyberbobjr commented 8 years ago

Nope, no more success. in my systemjs, the path to the generated SDK with the builder is "sdk", "shared" is for my internal ui component.

i'll try with angular-cli for test. Thanks regards BM

jonathan-casarrubias commented 8 years ago

Alright, I still think there is something wrong in the system-config.js.

If worth for something, this is the vanilla system.js configuration when using the angular-cli with only the SDK installed.

/***********************************************************************************************
 * User Configuration.
 **********************************************************************************************/
/** Map relative paths to URLs. */
const map: any = {
};

/** User packages configuration. */
const packages: any = {
};

////////////////////////////////////////////////////////////////////////////////////////////////
/***********************************************************************************************
 * Everything underneath this line is managed by the CLI.
 **********************************************************************************************/
const barrels: string[] = [
  // Angular specific barrels.
  '@angular/core',
  '@angular/common',
  '@angular/compiler',
  '@angular/http',
  '@angular/router',
  '@angular/platform-browser',
  '@angular/platform-browser-dynamic',

  // Thirdparty barrels.
  'rxjs',

  // App specific barrels.
  'app',
  'app/shared',
  /** @cli-barrel */
];

const cliSystemConfigPackages: any = {};
barrels.forEach((barrelName: string) => {
  cliSystemConfigPackages[barrelName] = { main: 'index' };
});

/** Type declaration for ambient System. */
declare var System: any;

// Apply the CLI SystemJS configuration.
System.config({
  map: {
    '@angular': 'vendor/@angular',
    'rxjs': 'vendor/rxjs',
    'main': 'main.js'
  },
  packages: cliSystemConfigPackages
});

// Apply the user's configuration.
System.config({ map, packages });

I place the sdk inside app/shared according the angular 2 styleguide 04-06 https://angular.io/styleguide#!#04-06 but if you want to keep placing it in app/sdk instead of app/shared, then just change that line in the system-config.

Cheers!!! Jon

cyberbobjr commented 8 years ago

Hi, i tested the most simple systemjs.config and generated the sdk inside the app/shared directory, but the error is still here :

zone.js:323 Error: (SystemJS) TypeError: Class extends value undefined is not a function or null at Object.eval (http://localhost:3000/app/shared/services/custom/Seminaire.js:27:54) at eval (http://localhost:3000/app/shared/services/custom/Seminaire.js:1720:4) at eval (http://localhost:3000/app/shared/services/custom/Seminaire.js:1721:3) at Object.eval (http://localhost:3000/app/shared/services/custom/index.js:6:10) Evaluating http://localhost:3000/app/shared/services/custom/Seminaire.js Evaluating http://localhost:3000/app/shared/services/custom/index.js Evaluating http://localhost:3000/app/shared/services/index.js Evaluating http://localhost:3000/app/shared/index.js Evaluating http://localhost:3000/app/shared/services/core/logger.service.js Evaluating http://localhost:3000/app/shared/services/core/index.js Evaluating http://localhost:3000/app/shared/services/custom/Organisateur.js Evaluating http://localhost:3000/app/ui/navbar.component.js Evaluating http://localhost:3000/app/app.component.js Evaluating http://localhost:3000/app/main.js Error loading http://localhost:3000/app/main.js

I tested with Google Chrome. With Firefox, the error is :

index_1.BaseLoopBackApi is not a constructor

inside the Seminaire.js

really really strange.

I modified the Seminaire.js like this :

const core_1 = require('@angular/core');
const http_1 = require('@angular/http');
const index_1 = require('../core/index');
const index_2 = require('../../models/index');
const lb_config_1 = require('../../lb.config');
require('rxjs/add/observable/throw');
require('rxjs/add/operator/map');
require('rxjs/add/operator/catch');
require('rxjs/add/operator/share');
console.log(index_1);

and the result in the console for console.log(index_1) is :

Object {}

i tried with console.log(index_2) but the result is the same : an empty object. But console.log(lb_config_1) and console.log(core_1) give me a correct result.

In the services/index.js i tried this :

function __export(m) {
    console.log(m);
    for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
/* tslint:disable */
__export(require('./core/index'));
__export(require('./custom/index'));

the output object "m" in the console is empty :

Object {}

I can't find the bug :(

cyberbobjr commented 8 years ago

in fact i switched to beta19 and all is working :/

jonathan-casarrubias commented 8 years ago

Wow this is far beyond something I have seen before, lets do this.. could you create a repo that I can see, I don't really need the backend, just a front end app with the generated SDK, I can verify how it was generated and where the issue is, otherwise this can take for weeks and I would not be able to launch a stable release until this is fixed.

Cheers Jon

cyberbobjr commented 8 years ago

Hi Jonathan, thanks you for your proposition, i’m in holidays for about a week, i’ll contact you after my vacation for your kindy proposition. Best regards BM

Le 25 juil. 2016 à 18:24, Jonathan Casarrubias notifications@github.com a écrit :

Wow this is far beyond something I have seen before, lets do this.. could you create a repo that I can see, I don't really need the backend, just a front end app with the generated SDK, I can verify how it was generated and where the issue is, otherwise this can take for weeks and I would not be able to launch a stable release until this is fixed.

Cheers Jon

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/jonathan-casarrubias/loopback-sdk-builder/issues/46#issuecomment-235004902, or mute the thread https://github.com/notifications/unsubscribe-auth/AAlFoBJLlwv6PHE6S2D89WSA9oEPGbKsks5qZOM-gaJpZM4JR2Nb.