Skip to content
Open

Ide #28

Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 1 addition & 19 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
module.exports = {
extends: ['plugin:@typescript-eslint/recommended', '@ehacke/eslint-config', 'plugin:import/typescript'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'import', 'simple-import-sort'],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'jsdoc/check-param-names': 'off',
'unicorn/expiring-todo-comments': 'error',
},
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx', '.d.ts', '.json'],
},
typescript: {},
},
jsdoc: {
mode: 'typescript',
},
},
extends: ['@ehacke/eslint-config-ts'],
};
3,809 changes: 2,048 additions & 1,761 deletions package-lock.json

Large diffs are not rendered by default.

85 changes: 45 additions & 40 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@asserted/models",
"description": "Shared asserted models",
"version": "10.0.7",
"version": "10.0.8-11",
"author": "Eric Hacke",
"bugs": {
"url": "https://github.com/assertedio/models/issues"
Expand All @@ -12,61 +12,66 @@
}
},
"dependencies": {
"@types/luxon": "^1.24.1",
"clean-deep": "^3.3.0",
"err": "^2.1.11",
"http-status": "^1.4.2",
"libphonenumber-js": "^1.7.55",
"lodash": "^4.17.19",
"luxon": "^1.24.1",
"ms": "^2.1.2",
"nanoid": "^3.1.10",
"@types/luxon": "^1.25.0",
"clean-deep": "^3.4.0",
"err": "^2.1.12",
"http-status": "^1.5.0",
"is-relative": "^1.0.0",
"is-valid-path": "^0.1.1",
"libphonenumber-js": "^1.9.6",
"lodash": "^4.17.20",
"luxon": "^1.25.0",
"ms": "^2.1.3",
"nanoid": "^3.1.20",
"normalize-path": "^3.0.0",
"shorthash": "0.0.2",
"shortid": "^2.2.15",
"shortid": "^2.2.16",
"ulid": "^2.3.0",
"validated-base": "^1.0.2"
},
"devDependencies": {
"@commitlint/cli": "^9.1.1",
"@commitlint/config-conventional": "^9.1.1",
"@ehacke/commitlint-config": "^1.0.3",
"@ehacke/eslint-config": "^1.1.6",
"@ehacke/prettier-config": "^1.0.2",
"@commitlint/cli": "^11.0.0",
"@commitlint/config-conventional": "^11.0.0",
"@ehacke/commitlint-config": "^2.0.0",
"@ehacke/eslint-config": "^2.0.2",
"@ehacke/eslint-config-ts": "^1.2.0",
"@ehacke/prettier-config": "^1.0.3",
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@types/fs-extra": "^9.0.1",
"@types/fs-extra": "^9.0.6",
"@types/getenv": "^1.0.0",
"@types/lodash": "^4.14.157",
"@types/mocha": "^8.0.0",
"@types/lodash": "^4.14.166",
"@types/mocha": "^8.2.0",
"@types/ms": "^0.7.31",
"@types/node": "^14.0.23",
"@types/node": "^14.14.16",
"@types/normalize-path": "^3.0.0",
"@types/shortid": "0.0.29",
"@typescript-eslint/eslint-plugin": "^3.6.1",
"@typescript-eslint/parser": "^3.6.1",
"@typescript-eslint/eslint-plugin": "^4.11.1",
"@typescript-eslint/parser": "^4.11.1",
"chai": "^4.2.0",
"class-validator": "^0.12.2",
"commitizen": "^4.1.2",
"commitlint": "^9.1.0",
"cz-conventional-changelog": "^3.2.0",
"commitizen": "^4.2.2",
"commitlint": "^11.0.0",
"cz-conventional-changelog": "^3.3.0",
"dotenv": "^8.2.0",
"eslint": "^7.5.0",
"eslint-import-resolver-typescript": "^2.0.0",
"eslint-plugin-simple-import-sort": "^5.0.3",
"eslint": "^7.16.0",
"eslint-import-resolver-typescript": "^2.3.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"fixpack": "^3.0.5",
"fs-extra": "^9.0.1",
"getenv": "^1.0.0",
"husky": "^4.2.5",
"lint-staged": "^10.2.10",
"mocha": "^8.0.1",
"husky": "^4.3.6",
"lint-staged": "^10.5.3",
"mocha": "^8.2.1",
"nyc": "^15.1.0",
"prettier": "^2.0.5",
"prettier": "^2.2.1",
"prettier-eslint-cli": "^5.0.0",
"sinon": "^9.0.2",
"ts-essentials": "^7.0.0",
"ts-node": "^8.10.2",
"sinon": "^9.2.2",
"ts-essentials": "^7.0.1",
"ts-node": "^9.1.1",
"tsconfig-paths": "^3.9.0",
"typedoc": "^0.17.8",
"typedoc-plugin-markdown": "^2.3.1",
"typescript": "^3.9.7"
"typedoc": "^0.20.0",
"typedoc-plugin-markdown": "^3.1.1",
"typescript": "^4.1.3"
},
"files": [
"dist/**/*.{js,ts,tsbuildinfo}",
Expand Down Expand Up @@ -114,15 +119,15 @@
]
},
"peerDependencies": {
"class-validator": "^0.11.1",
"class-validator": "^0.12.2",
"ts-essentials": "^7.0.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/assertedio/models.git"
},
"scripts": {
"beta": "npm version prerelease && npm publish",
"beta": "npm version prerelease && npm publish --tag beta",
"build": "rm -rf ./dist && tsc -p tsconfig.build.json",
"commit": "git-cz",
"docs": "typedoc --plugin typedoc-plugin-markdown --readme none --exclude \"tests/**/*.+(unit|it).+(ts|js)\"",
Expand Down
4 changes: 4 additions & 0 deletions src/requests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ export * from './projectAlert';
export * from './unsubscribeDetails';
export * from './build';
export * from './buildResult';
export * from './packageFile';
export * from './packageTree';
export * from './packagePatch';
export * from './packageFileUpdate';
78 changes: 78 additions & 0 deletions src/requests/packageFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import shorthash from 'shorthash';
import { isString } from 'lodash';
import normalize from 'normalize-path';
import isValidPath from 'is-valid-path';
import { IsString, Validate, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';

import { ValidatedBase } from 'validated-base';

const STARTS_RELATIVE_PATH = /^\.+\/+/;

export interface PackageFileInterface {
contents: string;
hash: string;
path: string;
}

export type PackageFileConstructorInterface = Omit<PackageFileInterface, 'hash'>;

const isOutsideDir = (filePath: string) => filePath.match(STARTS_RELATIVE_PATH);

export const validFilePath = (filePath: any): boolean =>
isString(filePath) && isValidPath(filePath) && !isOutsideDir(filePath) && !filePath.endsWith('/');

/* eslint-disable require-jsdoc, class-methods-use-this */

@ValidatorConstraint({ name: 'filePath', async: false })
export class FilePathValidator implements ValidatorConstraintInterface {
validate(value: any): Promise<boolean> | boolean {
return validFilePath(value);
}

defaultMessage(): string {
return 'Must be a valid path within the .asserted directory. No relative prefix.';
}
}

/* eslint-enable require-jsdoc, class-methods-use-this */

/**
* @class
*/
export class PackageFile extends ValidatedBase implements PackageFileInterface {
/**
* @param {PackageFileConstructorInterface} params
* @param {boolean} validate
*/
constructor(params: PackageFileConstructorInterface, validate = true) {
super();

this.contents = params.contents;
this.hash = PackageFile.getHash(this.contents);
this.path = normalize(params.path, false);

if (validate) {
this.validate();
}
}

@IsString()
contents: string;

@IsString()
hash: string;

@Validate(FilePathValidator)
path: string;

/**
* Get hash of contents
*
* @param {string} contents
* @returns {string}
*/
static getHash(contents: string): string {
// This is just salted so that an empty file still generates a hash
return `v1-${shorthash.unique(`VufLW-${contents}`)}`;
}
}
45 changes: 45 additions & 0 deletions src/requests/packageFileUpdate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import normalize from 'normalize-path';
import { isString } from 'lodash';
import { IsOptional, IsString, Validate } from 'class-validator';
import { ValidatedBase } from 'validated-base';
import { FilePathValidator, PackageFile } from './packageFile';

export interface PackageFileUpdateInterface {
contents: string | null;
hash: string | null;
path: string;
}

export type PackageFileUpdateConstructorInterface = Omit<PackageFileUpdateInterface, 'hash'>;

/**
* @class
*/
export class PackageFileUpdate extends ValidatedBase implements PackageFileUpdateInterface {
/**
* @param {PackageFileUpdateConstructorInterface} params
* @param {boolean} validate
*/
constructor(params: PackageFileUpdateConstructorInterface, validate = true) {
super();

this.contents = params.contents;
this.hash = isString(this.contents) ? PackageFile.getHash(this.contents) : null;
this.path = normalize(params.path, false);

if (validate) {
this.validate();
}
}

@IsOptional()
@IsString()
contents: string | null;

@IsOptional()
@IsString()
hash: string | null;

@Validate(FilePathValidator)
path: string;
}
84 changes: 84 additions & 0 deletions src/requests/packagePatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { ValidatedBase } from 'validated-base';
import { ArrayMinSize, IsArray, IsInstance, ValidateNested } from 'class-validator';
import Err from 'err';
import HTTP_STATUS from 'http-status';
import { PackageFileUpdate, PackageFileUpdateConstructorInterface, PackageFileUpdateInterface } from './packageFileUpdate';
import { RoutineConfig } from '../models';

export interface PackagePatchInterface {
files: PackageFileUpdateInterface[];
}

export interface PackagePatchConstructorInterface {
files: PackageFileUpdateConstructorInterface[];
}

export const validatePackagePatchFiles = (files: PackageFileUpdateInterface[]) => {
const packageJsonPatch = files.find(({ path }) => path === 'package.json');

if (packageJsonPatch) {
if (packageJsonPatch.contents === null) {
throw new Err('Cannot delete package.json', HTTP_STATUS.BAD_REQUEST);
}

try {
JSON.parse(packageJsonPatch.contents);
} catch {
throw new Err('package.json contains invalid JSON', HTTP_STATUS.BAD_REQUEST);
}
}

const routineJsonPatch = files.find(({ path }) => path === 'routine.json');

if (routineJsonPatch) {
if (routineJsonPatch.contents === null) {
throw new Err('Cannot delete routine.json', HTTP_STATUS.BAD_REQUEST);
}

let parsed;

try {
parsed = JSON.parse(routineJsonPatch.contents);
} catch {
throw new Err('routine.json contains invalid JSON', HTTP_STATUS.BAD_REQUEST);
}

try {
// Just validate config
// eslint-disable-next-line no-new
new RoutineConfig(parsed);
} catch (error) {
throw new Err(`Error in routine.json: ${error.message}`, HTTP_STATUS.BAD_REQUEST);
}
}
};

/**
* @class
*/
export class PackagePatch extends ValidatedBase implements PackagePatchInterface {
/**
* @param {PackagePatchConstructorInterface} params
* @param {boolean} [validate=true]
*/
constructor(params: PackagePatchConstructorInterface, validate = false) {
super();

this.files = (params.files || []).map((file) => new PackageFileUpdate(file));

if (this.files.length === 0) {
throw new Err('files must have a length greater than 0', HTTP_STATUS.BAD_REQUEST);
}

if (validate) {
validatePackagePatchFiles(this.files);
this.validate();
}
}

@IsArray()
@ValidateNested({ each: true })
@ArrayMinSize(1)
@IsInstance(PackageFileUpdate, { each: true })
files: PackageFileUpdateInterface[];
}
Loading