рдпрд╣ рдПрдХ рдФрд░ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдлреНрд░реЗрдорд╡рд░реНрдХ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред

рдкрд┐рдЫрд▓реА рдЧрд░реНрдорд┐рдпреЛрдВ рдореЗрдВ, рд╣реИрдмрд░ рдХреЗ рд▓рд┐рдП рдПрдХ рд▓реЗрдЦ рддреИрдпрд╛рд░ рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ , рдореИрдВ Npm рдкреИрдХреЗрдЬ рдкрд░ Node.js рдкрд░ рдмреИрдХрдПрдВрдб рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЛ рдкреИрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЖрд▓рд╕реА рдирд╣реАрдВ рдерд╛, рдЬрд┐рд╕рд╕реЗ рдпрд╣ рддреНрд╡рд░рд┐рдд рд╢реБрд░реБрдЖрдд рдХреЗ рд▓рд┐рдП рдПрдХ рдХреНрд▓реА-рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдмрди рдЧрдпрд╛ред


рдЗрд╕ рдмрд╛рдд рдХреА рдХреЛрдИ рдЙрдореНрдореАрдж рдирд╣реАрдВ рдереА рдХрд┐ рдореЗрд░реЗ рдЕрд▓рд╛рд╡рд╛ рдХреЛрдИ рднреА рд╢реБрд░реВ рдореЗрдВ рдЗрд╕ рдкреИрдХреЗрдЬ рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд░реЗрдЧрд╛ред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдЬрдм рдореИрдВрдиреЗ рдЕрдкрдиреА рдЬрд╝рд░реВрд░рдд рдХреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рдкреЗрд╢ рдХрд░рдХреЗ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛, рддреЛ рдореИрдВрдиреЗ рджреЗрдЦрд╛ рдХрд┐ рдПрдирдкреАрдПрдо рдкреИрдХреЗрдЬ рдореЗрдВ рдкреНрд░рддрд┐ рд╕рдкреНрддрд╛рд╣ рдХрдИ рджрд░реНрдЬрди рдбрд╛рдЙрдирд▓реЛрдб рд╣реЛрддреЗ рд╣реИрдВ, рдФрд░ рдЬреАрдердм рдкрд░ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ 12 рд╕реНрдЯрд╛рд░ рд╣реИрдВред рдЕрдЪреНрдЫреЗ рд▓реЛрдЧреЛрдВ рджреНрд╡рд╛рд░рд╛ рджрдпрд╛рд▓реБрддрд╛ рдореЗрдВ рд╡рд┐рддрд░рд┐рдд, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдореЗрд░рд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдкрд░рд┐рдпреЛрдЬрдирд╛ рдирд╣реАрдВред рдХреЗрд╡рд▓ 12 рддрд╛рд░реЗ, рд▓реЗрдХрд┐рди рдореЗрд░реЗ рд▓рд┐рдП рдпрд╣ рддрдп рдХрд░рдирд╛ рд╣реА рдХрд╛рдлреА рдерд╛ рдХрд┐ рдореИрдВ рдХрд░рдХрд╛рд╕ рдХрд╛ рд╡рд┐рдХрд╛рд╕ рдХрд░реВрдВрдЧрд╛ рдЬреИрд╕реЗ рдХрд┐ рдпрд╣ рди рдХреЗрд╡рд▓ рдореЗрд░реЗ рд▓рд┐рдП рдЬрд░реВрд░реА рдерд╛ред


рдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рд╢реБрд░реВ рдореЗрдВ рдореИрдВрдиреЗ рдмреИрдХрдПрдВрдб рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рд╣рд▓реНрдХрд╛ рдврд╛рдВрдЪрд╛ рдмрдирд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдерд╛, рд╡рд┐рдХрд╛рд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рджреМрд░рд╛рди рдореИрдВ рдЦреБрдж рдХреЛ рдпрд╣ рд╕рдордЭрд╛рдиреЗ рдореЗрдВ рдХрд╛рдордпрд╛рдм рд░рд╣рд╛ рдХрд┐ рдЗрд╕ рдмрд╛рдЗрдХ рдХреА рдЬрд░реВрд░рдд рдирд╣реАрдВ рдереАред рдФрд░ рд╡рд╣ рдХрд░рдХреИрд╢ рдПрдХ рдлреНрд░реЗрдорд╡рд░реНрдХ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдмрд▓реНрдХрд┐ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рд╕реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рд░реНрд╡рднреМрдорд┐рдХ рдЙрдкрдХрд░рдг рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред


рдЫрд╡рд┐


рдкрд╣рд▓реЗ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ, рдХреНрд▓реА-рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рддрд░реНрдХ рдЖрджрд┐рдо рдерд╛ред


  1. .
  2. karcass template .
  3. , ( - , ) ( ).
  4. , npm install.

:


рдЫрд╡рд┐


. , .


, : Application , , . , :


Application.ts
import Express from 'express'
import { AbstractConsoleCommand } from './Base/Console/AbstractConsoleCommand'
import { DbService } from './Database/Service/DbService'
import { HelpCommand } from './Base/Console/HelpCommand'
import { LoggerService } from './Logger/Service/LoggerService'
import { IssueService } from './Project/Service/IssueService'
import { GitlabService } from './Gitlab/Service/GitlabService'
import { LocalCacheService } from './Base/Service/LocalCacheService'
import { ProjectService } from './Project/Service/ProjectService'
import { GroupService } from './Project/Service/GroupService'
import { UserService } from './User/Service/UserService'
import { UpdateProjectsCommand } from './Gitlab/Console/UpdateProjectsCommand'
import { CreateMigrationCommand } from './Database/Console/CreateMigrationCommand'
import { MigrateCommand } from './Database/Console/MigrateCommand'
import { MigrateUndoCommand } from './Database/Console/MigrateUndoCommand'
import IssueController from './Project/Controller/IssueController'
import fs from 'fs'

export class Application {
    public http!: Express.Express

    // Services
    public localCacheService!: LocalCacheService
    public loggerService!: LoggerService
    public dbService!: DbService
    public gitlabService!: GitlabService
    public issueService!: IssueService
    public projectService!: ProjectService
    public groupService!: GroupService
    public userService!: UserService

    // Commands
    public helpCommand!: HelpCommand
    public createMigrationCommand!: CreateMigrationCommand
    public migrateCommand!: MigrateCommand
    public migrateUndoCommand!: MigrateUndoCommand
    public updateProjectsCommand!: UpdateProjectsCommand

    // Controllers
    public issueController!: IssueController

    public constructor(public readonly config: IConfig) {
        if (config.columns.length < 2) {
            throw new Error('There are too few columns :-(')
        }
    }

    public async run() {
        this.initializeServices()
        if (process.argv[2]) {
            this.initializeCommands()
            for (const command of Object.values(this)
                .filter((c: any) => c instanceof AbstractConsoleCommand) as AbstractConsoleCommand[]
            ) {
                if (command.name === process.argv[2]) {
                    await command.execute()
                    process.exit()
                }
            }
            await this.helpCommand.execute()
            process.exit()
        } else {
            this.runWebServer()
        }
    }

    protected runWebServer() {
        this.initCron()
        this.http = Express()
        this.http.use('/', Express.static('vue/dist'))
        this.http.use((req, res, next) => {
            if (req.url.indexOf('/api') === -1) {
                res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate')
                res.header('Expires', '-1')
                res.header('Pragma', 'no-cache')
                return res.send(fs.readFileSync('vue/dist/index.html').toString())
            }
            next()
        })
        this.http.use(Express.urlencoded())
        this.http.use(Express.json())
        this.http.listen(this.config.listen, () => console.log(`Listening on port ${this.config.listen}`))

        this.initializeControllers()
    }

    protected initCron() {
        if (this.config.gitlab.updateInterval) {
            setInterval(async () => {
                if (!this.updateProjectsCommand) {
                    this.updateProjectsCommand = new UpdateProjectsCommand(this)
                }
                await this.updateProjectsCommand.execute()
            }, this.config.gitlab.updateInterval * 1000)
        }
    }

    protected initializeServices() {
        this.localCacheService = new LocalCacheService(this)
        this.gitlabService = new GitlabService(this)
        this.loggerService = new LoggerService(this)
        this.dbService = new DbService(this)
        this.issueService = new IssueService(this)
        this.projectService = new ProjectService(this)
        this.groupService = new GroupService(this)
        this.userService = new UserService(this)
    }

    protected initializeCommands() {
        this.helpCommand = new HelpCommand(this)
        this.createMigrationCommand = new CreateMigrationCommand(this)
        this.migrateCommand = new MigrateCommand(this)
        this.migrateUndoCommand = new MigrateUndoCommand(this)
        this.updateProjectsCommand = new UpdateProjectsCommand(this)
    }

    protected initializeControllers() {
        this.issueController = new IssueController(this)
    }

}

ProjectService.ts
import { AbstractService } from '../../Base/Service/AbstractService'
import { Project } from '../Entity/Project'

export class ProjectService extends AbstractService {

    public get projectRepository() {
        return this.app.dbService.connection.getRepository(Project)
    }

    public async updateProjects(allTime = false) {
        await this.app.groupService.updateGroups()
        for (const data of await this.app.gitlabService.getProjects()) {
            let project = await this.getProject(data.id)

            if (!project) {
                project = this.projectRepository.create({ id: data.id })
            }
            project.name = data.name
            project.url = data.web_url
            project.updatedTimestamp = Math.round(new Date(data.last_activity_at).getTime() / 1000)
            project.groupId = data.namespace && data.namespace.kind === 'group' ? data.namespace.id : null
            await this.projectRepository.save(project)
            await this.app.issueService.updateProjectIssues(project, allTime)
        }
    }

    public async getProject(id: number): Promise<Project|undefined> {
        return id ? this.app.localCacheService.get(`project.${id}`, () => this.projectRepository.findOne(id)) : undefined
    }

}

, , , . , DI-, cli.


Application.ts , ┬л ┬╗. .


Application.ts
import CreateExpress, { Express } from 'express';
import { TwingEnvironment, TwingLoaderFilesystem } from 'twing';
import { Container } from '@karcass/container';
import { Cli } from '@karcass/cli';
import { Connection, createConnection } from 'typeorm';
import { CreateMigrationCommand, MigrateCommand, MigrateUndoCommand } from '@karcass/migration-commands';
import { createLogger } from './routines/createLogger';
import { Logger } from 'winston';
import { FrontPageController } from './SampleBundle/Controller/FrontPageController';
import { Message } from './SampleBundle/Entity/Message';
import { MessagesService } from './SampleBundle/Service/MessagesService';

export class Application {
    private container = new Container();
    private console = new Cli();
    private controllers: object[] = [];
    private http!: Express;

    public constructor(public readonly config: IConfig) { }

    public async run() {
        await this.initializeServices();

        if (process.argv[2]) {
            this.initializeCommands();
            await this.console.run();
        } else {
            this.runWebServer();
        }
    }

    protected runWebServer() {
        this.http = CreateExpress();
        this.http.use('/public', CreateExpress.static('public'));
        this.http.use(CreateExpress.urlencoded());
        this.http.listen(this.config.listen, () => console.log(`Listening on port ${this.config.listen}`));

        this.container.add<Express>('express', () => this.http);
        this.container.add(TwingEnvironment, () => new TwingEnvironment(new TwingLoaderFilesystem('src')));

        this.initializeControllers();
    }

    protected async initializeServices() {
        await this.container.addInplace<Logger>('logger', () => createLogger(this.config.logdir));
        const typeorm = await this.container.addInplace(Connection, () => createConnection({
            type: 'sqlite',
            database: 'db/sample.sqlite',
            entities: ['build/**/Entity/*.js'],
            migrations: ['build/**/Migrations/*.js'],
            logging: ['error', 'warn', 'migration'],
        }));
        this.container.add('Repository<Message>', () => typeorm.getRepository(Message));
        this.container.add(MessagesService);
    }

    protected initializeCommands() {
        this.console.add(CreateMigrationCommand, () => new CreateMigrationCommand());
        this.console.add(MigrateCommand, async () => new MigrateCommand(await this.container.get(Connection)));
        this.console.add(MigrateUndoCommand, async () => new MigrateUndoCommand(await this.container.get(Connection)));
    }

    protected async initializeControllers() {
        this.controllers.push(
            await this.container.inject(FrontPageController),
        );
    }

}

TypeScript :


FrontPageController.ts
import { Express } from 'express';
import { Dependency } from '@karcass/container';
import { TwingEnvironment } from 'twing';
import { AbstractController, QueryData } from './AbstractController';
import { MessagesService } from '../Service/MessagesService';

export class FrontPageController extends AbstractController {

    public constructor(
        @Dependency('express') protected express: Express,
        @Dependency(TwingEnvironment) protected twing: TwingEnvironment,
        @Dependency(MessagesService) protected messagesService: MessagesService,
    ) {
        super(express);

        this.onQuery('/', 'get', this.frontPageAction);
        this.onQuery('/', 'post', this.sendMessageAction);
    }

    public async sendMessageAction(data: QueryData) {
        await this.messagesService.addMessage(data.params.text);
        data.res.redirect('/');
    }

    public async frontPageAction() {
        if (await this.messagesService.isEmpty()) {
            await this.messagesService.createSampleMessages();
        }
        return this.twing.render('SampleBundle/Views/front.twig', {
            messages: await this.messagesService.getMessages(),
        });
    }

}

JavaScript, ┬л┬╗:


protected async initializeControllers() {
    this.controllers.push(
        new FrontPageController(
            await this.container.get('express'),
            await this.container.get(TwingEnvironment),
            await this.container.get(MessagesService),
        ),
    );
}

template karcass, : . , .


: TemplateReducer.ts TemplateReducer.js, TemplateReducer, :


interface TemplateReducerInterface {
    getConfigParameters(): Promise<ConfigParametersResult>
    getConfig(): Record<string, any>
    setConfig(config: Record<string, any>): void
    getDirectoriesForRemove(): Promise<string[]>
    getFilesForRemove(): Promise<string[]>
    getDependenciesForRemove(): Promise<string[]>
    getFilesContentReplacers(): Promise<ReplaceFileContentItem[]>
    finish(): Promise<void>
    getTestConfigSet(): Promise<Record<string, any>[]>
}

, , , - , karcass , JavaScript/TypeScript. -. - webpack. , - create-react-app ... , vue create.


TemplateReducerInterface, , . karcass:


hello index.js :


console.log('Hello, [replacethisname]!')

TemplateReducer.js, karcass' :


const reducer = require('@karcass/template-reducer')
const Type = reducer.ConfigParameterType

class TemplateReducer extends reducer.AbstractTemplateReducer {
    getConfigParameters() {
        return [
            { name: 'name', description: 'Please enter your name', type: Type.string },
        ]
    }
    async getFilesContentReplacers() {
        return [
            { filename: 'index.js', replacer: (content) => {
                return content.replace('[replacethisname]', this.config.name)
            } },
        ]
    }
    async finish() {
        console.log(`Application installed, to launch it execute\n  cd ${this.directoryName} && node index.js`)it.`)
    }
}
module.exports = { TemplateReducer }

, , , тАФ @karcass/template-reducer, , package.json:


npm init && npm install @karcass/template-reducer

, getDependenciesForRemove, karcass .


karcass . , .


рдЫрд╡рд┐


, karcass . github.com, :


npx karcass create helloworld https://github.com/karcass-ts/hello-world

, -, :


npx karcass create ooohhhh-ok-show-it

? , TemplateReducer helloworld- :


    getTestConfigSet() {
        return [
            { name: 'testname1' },
            { name: 'testname2' },
        ]
    }

:


npx karcass test www/karcass/hello

тАФ . , , , :


рдЫрд╡рд┐


рдореИрдВрдиреЗ рдХрд╛рд░рдХрд╛рд╕ рдХреА рд╕рднреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЗ рд╕рд╛рде рдПрдХ рд▓реЙрдиреНрдЧрдбреНрд░рд╛рдЗрд╡ рди рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛, рд▓реЗрдХрд┐рди рдкреНрд░рд╕реНрддреБрддрд┐ рдХреЗ рдЙрджреНрджреЗрд╢реНрдп рд╕реЗ рдПрдХ рдЫреЛрдЯреА рддрдереНрдп-рдЦреЛрдЬ рдиреЛрдЯ рддреИрдпрд╛рд░ рдХрд░рдирд╛ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдПрдХрддреНрд░ рдХрд░рдирд╛: рдХреЛрдИ рднреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрд░реЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛрдЧреА, рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдпрд╣ рдХрд╣рд╛рдБ рдЬрд╛рдирд╛ рд╣реИ рдФрд░ рдХреНрдпрд╛ рдЗрд╕рдХреЗ рд▓рд╛рдпрдХ рд╣реИред рдЗрд╕ рдмреАрдЪ, рдкреНрд░рд▓реЗрдЦрди рд▓рд┐рдЦрдирд╛ рдПрдХ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рд╣реИред


рдЧрд┐рддреВрдм рдкрд░ рдХрд░рдХрд╕ рднрдВрдбрд╛рд░ ;

Source: https://habr.com/ru/post/undefined/


All Articles