Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • jw_sonar
  • jw_sonar_backup
  • main
  • move-to-esm-only
  • open_tool_for_self_hosting
  • v5.0
  • v4.1
  • v4.2
8 results

Target

Select target project
No results found
Select Git revision
  • jw_sonar
  • jw_sonar_backup
  • main
  • move-to-esm-only
  • open_tool_for_self_hosting
  • v5.0
  • v4.1
  • v4.2
8 results
Show changes

Commits on Source 26

16 files
+ 571
7
Compare changes
  • Side-by-side
  • Inline

Files

+4 −1
Original line number Original line Diff line number Diff line
@@ -6,6 +6,9 @@ This repo contains some code that can be shared across node projects of Dojo.


These packages are needed :
These packages are needed :


- `ajv`
- `json5`
- `tar-stream`
- `winston`
- `winston`


## How to use it
## How to use it
@@ -13,5 +16,5 @@ These packages are needed :
By adding this repo as submodule
By adding this repo as submodule


```bash
```bash
git submodule add ssh://git@ssh.hesge.ch:10572/isc/projects/dojo/projects/shared/nodesharedcode.git shared
git submodule add ../../shared/nodesharedcode.git shared
```
```
 No newline at end of file
+69 −0
Original line number Original line Diff line number Diff line
import fs           from 'node:fs';
import path         from 'node:path';
import tar          from 'tar-stream';
import stream       from 'node:stream';
import { Writable } from 'stream';
import zlib         from 'zlib';


class ArchiveHelper {
    private async explore(absoluteBasePath: string, rootPath: string, pack: tar.Pack) {
        for ( let file of await fs.promises.readdir(rootPath) ) {
            if ( file === 'output.tar' ) {
                continue;
            }
            file = path.join(rootPath, file);
            const stat = await fs.promises.stat(file);
            if ( stat.isDirectory() ) {
                await this.explore(absoluteBasePath, file, pack);
                continue;
            }
            const entry = pack.entry({
                                         name: file.replace(absoluteBasePath, ''),
                                         size: stat.size
                                     }, (err) => {
                if ( err ) {
                    throw err;
                }
            });
            const stream = fs.createReadStream(file);
            stream.pipe(entry);
        }
    }

    private async compress(folderPath: string, tarDataStream: stream.Writable) {
        const pack = tar.pack();

        await this.explore(folderPath, folderPath, pack);

        pack.pipe(zlib.createGzip()).pipe(tarDataStream);
        pack.finalize();
    }

    public async getBase64(folderPath: string): Promise<string> {
        let data: any;
        const tarDataStream = new stream.Writable({
                                                      write(this: Writable, chunk: Buffer, _encoding: BufferEncoding, next: (error?: Error | null) => void) {
                                                          if ( data ) {
                                                              data += chunk.toString('hex');
                                                          } else {
                                                              data = chunk.toString('hex');
                                                          }
                                                          next();
                                                      }
                                                  });

        await this.compress(folderPath, tarDataStream);

        await (new Promise((resolve, reject) => {
            tarDataStream.on('close', () => {
                resolve(0);
            });
        }));

        return Buffer.from(data, 'hex').toString('base64');
    }
}


export default new ArchiveHelper();
 No newline at end of file
+65 −0
Original line number Original line Diff line number Diff line
import Ajv, { ErrorObject, JTDSchemaType } from 'ajv/dist/jtd';
import fs                                  from 'fs';
import ExerciceResultsFile                 from '../types/Dojo/ExerciceResultsFile';
import JSON5                               from 'json5';


class ExerciceHelper {
    validateResultFile(resultsFilePathOrStr: string, isFile: boolean = true): { results: ExerciceResultsFile | undefined, isValid: boolean, errors: Array<ErrorObject<string, Record<string, any>, unknown> | string> | null | undefined } {
        const ajv = new Ajv();

        const schema: JTDSchemaType<ExerciceResultsFile> = {
            properties          : {
                success: { type: 'boolean' }
            },
            optionalProperties  : {
                successfulTests: { type: 'uint32' },
                failedTests    : { type: 'uint32' },

                successfulTestsList: {
                    elements: {
                        type: 'string'
                    }
                },
                failedTestsList    : {
                    elements: {
                        type: 'string'
                    }
                }
            },
            additionalProperties: false
        };

        const validator = ajv.compile(schema);

        try {
            const results = JSON5.parse(isFile ? fs.readFileSync(resultsFilePathOrStr, 'utf8') : resultsFilePathOrStr);
            const isValid = validator(results);

            if ( isValid ) {
                if ( results.successfulTests === undefined && results.successfulTestsList !== undefined ) {
                    results.successfulTests = results.successfulTestsList.length;
                }

                if ( results.failedTests === undefined && results.failedTestsList !== undefined ) {
                    results.failedTests = results.failedTestsList.length;
                }
            }

            return {
                results: isValid ? results : results as any,
                isValid: isValid,
                errors : validator.errors
            };
        } catch ( error ) {
            return {
                results: undefined,
                isValid: false,
                errors : [ `JSON5 invalid : ${ JSON.stringify(error) }` ]
            };
        }
    }
}


export default new ExerciceHelper();
 No newline at end of file
Original line number Original line Diff line number Diff line
import fs   from 'fs/promises';
import path from 'path';


class Toolbox {
class Toolbox {
    public urlToPath(url: string): string {
    public urlToPath(url: string): string {
        return url.replace(/^([a-z]{3,5}:\/{2})?[a-z.@]+(:[0-9]{1,5})?.(.*)/, '$3').replace('.git', '');
        return url.replace(/^([a-z]{3,5}:\/{2})?[a-z.@]+(:[0-9]{1,5})?.(.*)/, '$3').replace('.git', '');
    }
    }

    /*
     Source of getAllFiles and getTotalSize (modified for this project): https://coderrocketfuel.com/article/get-the-total-size-of-all-files-in-a-directory-using-node-js
     */
    private async getAllFiles(dirPath: string, arrayOfFiles: Array<string> = []): Promise<Array<string>> {
        let files = await fs.readdir(dirPath);

        await Promise.all(files.map(async file => {
            if ( (await fs.stat(dirPath + '/' + file)).isDirectory() ) {
                arrayOfFiles = await this.getAllFiles(dirPath + '/' + file, arrayOfFiles);
            } else {
                arrayOfFiles.push(path.join(dirPath, file));
            }
        }));

        return arrayOfFiles;
    };

    private async getTotalSize(directoryPath: string): Promise<number> {
        const arrayOfFiles = await this.getAllFiles(directoryPath);

        let totalSize = 0;

        for ( const filePath of arrayOfFiles ) {
            totalSize += (await fs.stat(filePath)).size;
        }

        return totalSize;
    };

    get fs() {
        return {
            getAllFiles : this.getAllFiles.bind(this),
            getTotalSize: this.getTotalSize.bind(this)
        };
    }

    public snakeToCamel(str: string): string {
        return str.toLowerCase().replace(/([-_][a-z])/g, (group: string) => group.toUpperCase().replace('-', '').replace('_', ''));
    }

    public getKeysWithPrefix(obj: object, prefix: string): Array<string> {
        return Object.keys(obj).filter(key => key.startsWith(prefix));
    }
}
}




Original line number Original line Diff line number Diff line
@@ -8,6 +8,7 @@ declare global {
        toBoolean: () => boolean;
        toBoolean: () => boolean;
        capitalizingFirstLetter: () => string;
        capitalizingFirstLetter: () => string;
        capitalizeName: () => string;
        capitalizeName: () => string;
        convertWithEnvVars: () => string;
    }
    }
}
}


@@ -17,6 +18,7 @@ function registerAll() {
    registerStringToBoolean();
    registerStringToBoolean();
    registerStringCapitalizingFirstLetter();
    registerStringCapitalizingFirstLetter();
    registerStringCapitalizeName();
    registerStringCapitalizeName();
    registerStringConvertWithEnvVars();
}
}


function registerBigIntJson() {
function registerBigIntJson() {
@@ -55,6 +57,14 @@ function registerStringCapitalizeName() {
    };
    };
}
}


function registerStringConvertWithEnvVars() {
    String.prototype.convertWithEnvVars = function (this: string): string {
        return this.replace(/\${?([a-zA-Z0-9_]+)}?/g, (_match: string, p1: string) => {
            return process.env[p1] || '';
        });
    };
}

registerAll();
registerAll();




+148 −0
Original line number Original line Diff line number Diff line
Source: recursive-readdir-files
===
Modified for Dojo
===

## Usage

```js
import recursiveReaddirFiles from 'recursive-readdir-files';


const files = await recursiveReaddirFiles(process.cwd(), {
    ignored: /\/(node_modules|\.git)/
});

// `files` is an array
console.log(files);
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
// [
//   {
//     dev: 16777233,
//     mode: 33188,
//     nlink: 1,
//     uid: 501,
//     gid: 20,
//     rdev: 0,
//     blksize: 4096,
//     ino: 145023089,
//     size: 89,
//     blocks: 8,
//     atimeMs: 1649303678077.934,
//     mtimeMs: 1649303676847.1777,
//     ctimeMs: 1649303676847.1777,
//     birthtimeMs: 1649301118132.6782,
//     atime: 2022-04-07T03:54:38.078Z,
//     mtime: 2022-04-07T03:54:36.847Z,
//     ctime: 2022-04-07T03:54:36.847Z,
//     birthtime: 2022-04-07T03:11:58.133Z,
//     name: 'watch.ts',
//     path: '/Users/xxx/watch.ts',
//     ext: 'ts'
//   },
//   // ...
// ]
```

Or

```js
recursiveReaddirFiles(process.cwd(), {
    ignored: /\/(node_modules|\.git)/
}, (filepath, state) => {
    console.log(filepath);
    // 👉 /Users/xxx/watch.ts
    console.log(state.isFile());      // 👉 true
    console.log(state.isDirectory()); // 👉 false
    console.log(state);
    // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    // {
    //   dev: 16777233,
    //   mode: 33188,
    //   nlink: 1,
    //   uid: 501,
    //   gid: 20,
    //   rdev: 0,
    //   blksize: 4096,
    //   ino: 145023089,
    //   size: 89,
    //   blocks: 8,
    //   atimeMs: 1649303678077.934,
    //   mtimeMs: 1649303676847.1777,
    //   ctimeMs: 1649303676847.1777,
    //   birthtimeMs: 1649301118132.6782,
    //   atime: 2022-04-07T03:54:38.078Z,
    //   mtime: 2022-04-07T03:54:36.847Z,
    //   ctime: 2022-04-07T03:54:36.847Z,
    //   birthtime: 2022-04-07T03:11:58.133Z,
    //   name: 'watch.ts',
    //   path: '/Users/xxx/watch.ts',
    //   ext: 'ts'
    // }
})
```

## Options

```ts
export interface RecursiveReaddirFilesOptions {
    /**
     * Ignore files
     * @example `/\/(node_modules|\.git)/`
     */
    ignored?: RegExp;
    /**
     * Specifies a list of `glob` patterns that match files to be included in compilation.
     * @example `/(\.json)$/`
     */
    include?: RegExp;
    /**
     * Specifies a list of files to be excluded from compilation.
     * @example `/(package\.json)$/`
     */
    exclude?: RegExp;
    /** Provide filtering methods to filter data. */
    filter?: (item: IFileDirStat) => boolean;
    /** Do not give the absolute path but the relative one from the root folder */
    replacePathByRelativeOne?: boolean;
    /** Remove stats that are not necessary for transfert */
    liteStats?: boolean;
}
```

## Result

```ts
import fs from 'node:fs';


export interface IFileDirStat extends Partial<fs.Stats> {
    /**
     * @example `/a/sum.jpg` => `sum.jpg`
     */
    name: string;
    /**
     * @example `/basic/src/utils/sum.ts`
     */
    path: string;
    /**
     * @example `/a/b.jpg` => `jpg`
     */
    ext?: string;
}


declare type Callback = (filepath: string, stat: IFileDirStat) => void;
export default function recursiveReaddirFiles(rootPath: string, options?: RecursiveReaddirFilesOptions, callback?: Callback): Promise<IFileDirStat[]>;
export { recursiveReaddirFiles };
export declare const getStat: (filepath: string) => Promise<IFileDirStat>;
/**
 * Get ext
 * @param {String} filePath `/a/b.jpg` => `jpg`
 */
export declare const getExt: (filePath: string) => string;
```

## License

Licensed under the MIT License.
Original line number Original line Diff line number Diff line
import fs   from 'node:fs';
import path from 'node:path';


export interface RecursiveReaddirFilesOptions {
    /**
     * Ignore files
     * @example `/\/(node_modules|\.git)/`
     */
    ignored?: RegExp;
    /**
     * Specifies a list of `glob` patterns that match files to be included in compilation.
     * @example `/(\.json)$/`
     */
    include?: RegExp;
    /**
     * Specifies a list of files to be excluded from compilation.
     * @example `/(package\.json)$/`
     */
    exclude?: RegExp;
    /** Provide filtering methods to filter data. */
    filter?: (item: IFileDirStat) => boolean;
    /** Do not give the absolute path but the relative one from the root folder */
    replacePathByRelativeOne?: boolean;
    /** Remove stats that are not necessary for transfert */
    liteStats?: boolean;
}


export interface IFileDirStat extends Partial<fs.Stats> {
    /**
     * @example `/a/sum.jpg` => `sum.jpg`
     */
    name: string;
    /**
     * @example `/basic/src/utils/sum.ts`
     */
    path: string;
    /**
     * @example `/a/b.jpg` => `jpg`
     */
    ext?: string;
}


type Callback = (filepath: string, stat: IFileDirStat) => void;


class RecursiveFilesStats {
    async explore(rootPath: string, options: RecursiveReaddirFilesOptions = {}, callback?: Callback): Promise<IFileDirStat[]> {
        return this.getFiles(`${ path.resolve(rootPath) }/`, rootPath, options, [], callback);
    }

    private async getFiles(absoluteBasePath: string, rootPath: string, options: RecursiveReaddirFilesOptions = {}, files: IFileDirStat[] = [], callback?: Callback): Promise<IFileDirStat[]> {
        const {
                  ignored, include, exclude, filter
              } = options;
        const filesData = await fs.promises.readdir(rootPath);
        const fileDir: IFileDirStat[] = filesData.map((file) => ({
            name: file, path: path.join(rootPath, file)
        })).filter((item) => {
            if ( include && include.test(item.path) ) {
                return true;
            }
            if ( exclude && exclude.test(item.path) ) {
                return false;
            }
            if ( ignored ) {
                return !ignored.test(item.path);
            }
            return true;
        });
        if ( callback ) {
            fileDir.map(async (item: IFileDirStat) => {
                const stat = await this.getStat(item.path, absoluteBasePath, options);
                if ( stat.isDirectory!() ) {
                    await this.getFiles(absoluteBasePath, item.path, options, [], callback);
                }
                callback(item.path, stat);
            });
        } else {
            await Promise.all(fileDir.map(async (item: IFileDirStat) => {
                const stat = await this.getStat(item.path, absoluteBasePath, options);
                if ( stat.isDirectory!() ) {
                    const arr = await this.getFiles(absoluteBasePath, item.path, options, []);
                    files = files.concat(arr);
                } else if ( stat.isFile!() ) {
                    files.push(stat);
                }
            }));
        }
        return files.filter((item) => {
            if ( filter && typeof filter === 'function' ) {
                return filter(item);
            }
            return true;
        });
    }

    private async getStat(filepath: string, absoluteRootPath: string, options: RecursiveReaddirFilesOptions): Promise<IFileDirStat> {
        const stat = (await fs.promises.stat(filepath)) as IFileDirStat;
        stat.ext = '';
        if ( stat.isFile!() ) {
            stat.ext = this.getExt(filepath);
            stat.name = path.basename(filepath);
            stat.path = path.resolve(filepath);
        }

        if ( options.replacePathByRelativeOne && stat.path ) {
            stat.path = stat.path.replace(absoluteRootPath, '');
        }

        if ( options.liteStats ) {
            delete stat.dev;
            delete stat.nlink;
            delete stat.uid;
            delete stat.gid;
            delete stat.rdev;
            delete stat.blksize;
            delete stat.ino;
            delete stat.blocks;
            delete stat.atimeMs;
            delete stat.mtimeMs;
            delete stat.ctimeMs;
            delete stat.birthtimeMs;
            delete stat.atime;
            //delete stat.mtime;
            delete stat.ctime;
            //delete stat.birthtime;
            //delete stat.mode;
        }

        return stat;
    };

    /**
     * Get ext
     * @param {String} filePath `/a/b.jpg` => `jpg`
     */
    private getExt(filePath: string): string {
        return path.extname(filePath).replace(/^\./, '').toLowerCase();
    }
}


export default new RecursiveFilesStats();
Original line number Original line Diff line number Diff line
@@ -2,7 +2,7 @@ interface DojoResponse<T> {
    timestamp: string;
    timestamp: string;
    code: number;
    code: number;
    description: string;
    description: string;
    sessionToken: string;
    sessionToken: string | null;
    data: T;
    data: T;
}
}


+16 −0
Original line number Original line Diff line number Diff line
import ImmutableFileDescriptor from './ImmutableFileDescriptor';


interface EnonceFile {
    dojoEnonceVersion: number,
    version: number,

    immutable: Array<ImmutableFileDescriptor>

    result: {
        container: string, volume: string
    }
}


export default EnonceFile;
 No newline at end of file
+12 −0
Original line number Original line Diff line number Diff line
interface ExerciceResultsFile {
    success: boolean;

    successfulTests?: number;
    failedTests?: number;

    successfulTestsList?: Array<string>;
    failedTestsList?: Array<string>;
}


export default ExerciceResultsFile;
 No newline at end of file
+8 −0
Original line number Original line Diff line number Diff line
interface ImmutableFileDescriptor {
    description: string,
    path: string,
    isDirectory: boolean,
}


export default ImmutableFileDescriptor;
 No newline at end of file
+16 −0
Original line number Original line Diff line number Diff line
interface GitlabFile {
    file_name: string,
    file_path: string,
    size: number,
    encoding: string,
    content_sha256: string,
    ref: string,
    blob_id: string,
    commit_id: string,
    last_commit_id: string,
    execute_filemode: boolean,
    content: string,
}


export default GitlabFile;
 No newline at end of file
Original line number Original line Diff line number Diff line
@@ -2,10 +2,10 @@ import GitlabUser from './GitlabUser';




interface GitlabMember extends GitlabUser {
interface GitlabMember extends GitlabUser {
    'access_level': number,
    access_level: number,
    'created_at': string,
    created_at: string,
    'created_by': GitlabUser,
    created_by: GitlabUser,
    'expires_at': string | null
    expires_at: string | null
}
}




Original line number Original line Diff line number Diff line
@@ -8,7 +8,9 @@ enum GitlabRoutes {
    REPOSITORY_MEMBER_ADD       = '/projects/{{id}}/members',
    REPOSITORY_MEMBER_ADD       = '/projects/{{id}}/members',
    REPOSITORY_MEMBERS_GET      = '/projects/{{id}}/members/all',
    REPOSITORY_MEMBERS_GET      = '/projects/{{id}}/members/all',
    REPOSITORY_VARIABLES_ADD    = '/projects/{{id}}/variables',
    REPOSITORY_VARIABLES_ADD    = '/projects/{{id}}/variables',
    REPOSITORY_BRANCHES_PROTECT = '/projects/{{id}}/protected_branches'
    REPOSITORY_BRANCHES_PROTECT = '/projects/{{id}}/protected_branches',
    REPOSITORY_TREE             = '/projects/{{id}}/repository/tree',
    REPOSITORY_FILE             = '/projects/{{id}}/repository/files/{{filePath}}',
}
}




+13 −0
Original line number Original line Diff line number Diff line
import GitlabTreeFileType from './GitlabTreeFileType';


interface GitlabTreeFile {
    id: number,
    name: string,
    type: GitlabTreeFileType,
    path: string,
    mode: string
}


export default GitlabTreeFile;
 No newline at end of file
+8 −0
Original line number Original line Diff line number Diff line
enum GitlabTreeFileType {
    TREE   = 'tree',
    BLOB   = 'blob',
    COMMIT = 'commit'
}


export default GitlabTreeFileType;