added doga

This commit is contained in:
szabomarton
2025-02-25 09:55:29 +01:00
parent 5174ab4cc4
commit 13254e5623
1149 changed files with 80161 additions and 0 deletions

8
25_02_24/node_modules/json-server/lib/app.d.ts generated vendored Normal file
View File

@@ -0,0 +1,8 @@
import { App } from '@tinyhttp/app';
import { Low } from 'lowdb';
import { Data } from './service.js';
export type AppOptions = {
logger?: boolean;
static?: string[];
};
export declare function createApp(db: Low<Data>, options?: AppOptions): App<import("@tinyhttp/app").Request, import("@tinyhttp/app").Response<unknown>>;

112
25_02_24/node_modules/json-server/lib/app.js generated vendored Normal file
View File

@@ -0,0 +1,112 @@
import { dirname, isAbsolute, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { App } from '@tinyhttp/app';
import { cors } from '@tinyhttp/cors';
import { Eta } from 'eta';
import { json } from 'milliparsec';
import sirv from 'sirv';
import { isItem, Service } from './service.js';
const __dirname = dirname(fileURLToPath(import.meta.url));
const isProduction = process.env['NODE_ENV'] === 'production';
const eta = new Eta({
views: join(__dirname, '../views'),
cache: isProduction,
});
export function createApp(db, options = {}) {
// Create service
const service = new Service(db);
// Create app
const app = new App();
// Static files
app.use(sirv('public', { dev: !isProduction }));
options.static
?.map((path) => (isAbsolute(path) ? path : join(process.cwd(), path)))
.forEach((dir) => app.use(sirv(dir, { dev: !isProduction })));
// CORS
app
.use((req, res, next) => {
return cors({
allowedHeaders: req.headers['access-control-request-headers']
?.split(',')
.map((h) => h.trim()),
})(req, res, next);
})
.options('*', cors());
// Body parser
// @ts-expect-error expected
app.use(json());
app.get('/', (_req, res) => res.send(eta.render('index.html', { data: db.data })));
app.get('/:name', (req, res, next) => {
const { name = '' } = req.params;
const query = Object.fromEntries(Object.entries(req.query)
.map(([key, value]) => {
if (['_start', '_end', '_limit', '_page', '_per_page'].includes(key) &&
typeof value === 'string') {
return [key, parseInt(value)];
}
else {
return [key, value];
}
})
.filter(([, value]) => !Number.isNaN(value)));
res.locals['data'] = service.find(name, query);
next?.();
});
app.get('/:name/:id', (req, res, next) => {
const { name = '', id = '' } = req.params;
res.locals['data'] = service.findById(name, id, req.query);
next?.();
});
app.post('/:name', async (req, res, next) => {
const { name = '' } = req.params;
if (isItem(req.body)) {
res.locals['data'] = await service.create(name, req.body);
}
next?.();
});
app.put('/:name', async (req, res, next) => {
const { name = '' } = req.params;
if (isItem(req.body)) {
res.locals['data'] = await service.update(name, req.body);
}
next?.();
});
app.put('/:name/:id', async (req, res, next) => {
const { name = '', id = '' } = req.params;
if (isItem(req.body)) {
res.locals['data'] = await service.updateById(name, id, req.body);
}
next?.();
});
app.patch('/:name', async (req, res, next) => {
const { name = '' } = req.params;
if (isItem(req.body)) {
res.locals['data'] = await service.patch(name, req.body);
}
next?.();
});
app.patch('/:name/:id', async (req, res, next) => {
const { name = '', id = '' } = req.params;
if (isItem(req.body)) {
res.locals['data'] = await service.patchById(name, id, req.body);
}
next?.();
});
app.delete('/:name/:id', async (req, res, next) => {
const { name = '', id = '' } = req.params;
res.locals['data'] = await service.destroyById(name, id, req.query['_dependent']);
next?.();
});
app.use('/:name', (req, res) => {
const { data } = res.locals;
if (data === undefined) {
res.sendStatus(404);
}
else {
if (req.method === 'POST')
res.status(201);
res.json(data);
}
});
return app;
}

2
25_02_24/node_modules/json-server/lib/bin.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/env node
export {};

183
25_02_24/node_modules/json-server/lib/bin.js generated vendored Normal file
View File

@@ -0,0 +1,183 @@
#!/usr/bin/env node
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
import { extname } from 'node:path';
import { parseArgs } from 'node:util';
import chalk from 'chalk';
import { watch } from 'chokidar';
import JSON5 from 'json5';
import { Low } from 'lowdb';
import { DataFile, JSONFile } from 'lowdb/node';
import { fileURLToPath } from 'node:url';
import { createApp } from './app.js';
import { Observer } from './observer.js';
function help() {
console.log(`Usage: json-server [options] <file>
Options:
-p, --port <port> Port (default: 3000)
-h, --host <host> Host (default: localhost)
-s, --static <dir> Static files directory (multiple allowed)
--help Show this message
--version Show version number
`);
}
// Parse args
function args() {
try {
const { values, positionals } = parseArgs({
options: {
port: {
type: 'string',
short: 'p',
default: process.env['PORT'] ?? '3000',
},
host: {
type: 'string',
short: 'h',
default: process.env['HOST'] ?? 'localhost',
},
static: {
type: 'string',
short: 's',
multiple: true,
default: [],
},
help: {
type: 'boolean',
},
version: {
type: 'boolean',
},
// Deprecated
watch: {
type: 'boolean',
short: 'w',
},
},
allowPositionals: true,
});
// --version
if (values.version) {
const pkg = JSON.parse(readFileSync(fileURLToPath(new URL('../package.json', import.meta.url)), 'utf-8'));
console.log(pkg.version);
process.exit();
}
// Handle --watch
if (values.watch) {
console.log(chalk.yellow('--watch/-w can be omitted, JSON Server 1+ watches for file changes by default'));
}
if (values.help || positionals.length === 0) {
help();
process.exit();
}
// App args and options
return {
file: positionals[0] ?? '',
port: parseInt(values.port),
host: values.host,
static: values.static,
};
}
catch (e) {
if (e.code === 'ERR_PARSE_ARGS_UNKNOWN_OPTION') {
console.log(chalk.red(e.message.split('.')[0]));
help();
process.exit(1);
}
else {
throw e;
}
}
}
const { file, port, host, static: staticArr } = args();
if (!existsSync(file)) {
console.log(chalk.red(`File ${file} not found`));
process.exit(1);
}
// Handle empty string JSON file
if (readFileSync(file, 'utf-8').trim() === '') {
writeFileSync(file, '{}');
}
// Set up database
let adapter;
if (extname(file) === '.json5') {
adapter = new DataFile(file, {
parse: JSON5.parse,
stringify: JSON5.stringify,
});
}
else {
adapter = new JSONFile(file);
}
const observer = new Observer(adapter);
const db = new Low(observer, {});
await db.read();
// Create app
const app = createApp(db, { logger: false, static: staticArr });
function logRoutes(data) {
console.log(chalk.bold('Endpoints:'));
if (Object.keys(data).length === 0) {
console.log(chalk.gray(`No endpoints found, try adding some data to ${file}`));
return;
}
console.log(Object.keys(data)
.map((key) => `${chalk.gray(`http://${host}:${port}/`)}${chalk.blue(key)}`)
.join('\n'));
}
const kaomojis = ['♡⸜(˶˃ ᵕ ˂˶)⸝♡', '♡( ◡‿◡ )', '( ˶ˆ ᗜ ˆ˵ )', '(˶ᵔ ᵕ ᵔ˶)'];
function randomItem(items) {
const index = Math.floor(Math.random() * items.length);
return items.at(index) ?? '';
}
app.listen(port, () => {
console.log([
chalk.bold(`JSON Server started on PORT :${port}`),
chalk.gray('Press CTRL-C to stop'),
chalk.gray(`Watching ${file}...`),
'',
chalk.magenta(randomItem(kaomojis)),
'',
chalk.bold('Index:'),
chalk.gray(`http://localhost:${port}/`),
'',
chalk.bold('Static files:'),
chalk.gray('Serving ./public directory if it exists'),
'',
].join('\n'));
logRoutes(db.data);
});
// Watch file for changes
if (process.env['NODE_ENV'] !== 'production') {
let writing = false; // true if the file is being written to by the app
let prevEndpoints = '';
observer.onWriteStart = () => {
writing = true;
};
observer.onWriteEnd = () => {
writing = false;
};
observer.onReadStart = () => {
prevEndpoints = JSON.stringify(Object.keys(db.data).sort());
};
observer.onReadEnd = (data) => {
if (data === null) {
return;
}
const nextEndpoints = JSON.stringify(Object.keys(data).sort());
if (prevEndpoints !== nextEndpoints) {
console.log();
logRoutes(data);
}
};
watch(file).on('change', () => {
// Do no reload if the file is being written to by the app
if (!writing) {
db.read().catch((e) => {
if (e instanceof SyntaxError) {
return console.log(chalk.red(['', `Error parsing ${file}`, e.message].join('\n')));
}
console.log(e);
});
}
});
}

11
25_02_24/node_modules/json-server/lib/observer.d.ts generated vendored Normal file
View File

@@ -0,0 +1,11 @@
import { Adapter } from 'lowdb';
export declare class Observer<T> {
#private;
onReadStart: () => void;
onReadEnd: (data: T | null) => void;
onWriteStart: () => void;
onWriteEnd: () => void;
constructor(adapter: Adapter<T>);
read(): Promise<T | null>;
write(arg: T): Promise<void>;
}

30
25_02_24/node_modules/json-server/lib/observer.js generated vendored Normal file
View File

@@ -0,0 +1,30 @@
// Lowdb adapter to observe read/write events
export class Observer {
#adapter;
onReadStart = function () {
return;
};
onReadEnd = function () {
return;
};
onWriteStart = function () {
return;
};
onWriteEnd = function () {
return;
};
constructor(adapter) {
this.#adapter = adapter;
}
async read() {
this.onReadStart();
const data = await this.#adapter.read();
this.onReadEnd(data);
return data;
}
async write(arg) {
this.onWriteStart();
await this.#adapter.write(arg);
this.onWriteEnd();
}
}

38
25_02_24/node_modules/json-server/lib/service.d.ts generated vendored Normal file
View File

@@ -0,0 +1,38 @@
import { Low } from 'lowdb';
export type Item = Record<string, unknown>;
export type Data = Record<string, Item[] | Item>;
export declare function isItem(obj: unknown): obj is Item;
export declare function isData(obj: unknown): obj is Record<string, Item[]>;
export type PaginatedItems = {
first: number;
prev: number | null;
next: number | null;
last: number;
pages: number;
items: number;
data: Item[];
};
export declare class Service {
#private;
constructor(db: Low<Data>);
has(name: string): boolean;
findById(name: string, id: string, query: {
_embed?: string[] | string;
}): Item | undefined;
find(name: string, query?: {
[key: string]: unknown;
_embed?: string | string[];
_sort?: string;
_start?: number;
_end?: number;
_limit?: number;
_page?: number;
_per_page?: number;
}): Item[] | PaginatedItems | Item | undefined;
create(name: string, data?: Omit<Item, 'id'>): Promise<Item | undefined>;
update(name: string, body?: Item): Promise<Item | undefined>;
patch(name: string, body?: Item): Promise<Item | undefined>;
updateById(name: string, id: string, body?: Item): Promise<Item | undefined>;
patchById(name: string, id: string, body?: Item): Promise<Item | undefined>;
destroyById(name: string, id: string, dependent?: string | string[]): Promise<Item | undefined>;
}

333
25_02_24/node_modules/json-server/lib/service.js generated vendored Normal file
View File

@@ -0,0 +1,333 @@
import { randomBytes } from 'node:crypto';
import { getProperty } from 'dot-prop';
import inflection from 'inflection';
import sortOn from 'sort-on';
export function isItem(obj) {
return typeof obj === 'object' && obj !== null;
}
export function isData(obj) {
if (typeof obj !== 'object' || obj === null) {
return false;
}
const data = obj;
return Object.values(data).every((value) => Array.isArray(value) && value.every(isItem));
}
var Condition;
(function (Condition) {
Condition["lt"] = "lt";
Condition["lte"] = "lte";
Condition["gt"] = "gt";
Condition["gte"] = "gte";
Condition["ne"] = "ne";
Condition["default"] = "";
})(Condition || (Condition = {}));
function isCondition(value) {
return Object.values(Condition).includes(value);
}
function ensureArray(arg = []) {
return Array.isArray(arg) ? arg : [arg];
}
function embed(db, name, item, related) {
if (inflection.singularize(related) === related) {
const relatedData = db.data[inflection.pluralize(related)];
if (!relatedData) {
return item;
}
const foreignKey = `${related}Id`;
const relatedItem = relatedData.find((relatedItem) => {
return relatedItem['id'] === item[foreignKey];
});
return { ...item, [related]: relatedItem };
}
const relatedData = db.data[related];
if (!relatedData) {
return item;
}
const foreignKey = `${inflection.singularize(name)}Id`;
const relatedItems = relatedData.filter((relatedItem) => relatedItem[foreignKey] === item['id']);
return { ...item, [related]: relatedItems };
}
function nullifyForeignKey(db, name, id) {
const foreignKey = `${inflection.singularize(name)}Id`;
Object.entries(db.data).forEach(([key, items]) => {
// Skip
if (key === name)
return;
// Nullify
if (Array.isArray(items)) {
items.forEach((item) => {
if (item[foreignKey] === id) {
item[foreignKey] = null;
}
});
}
});
}
function deleteDependents(db, name, dependents) {
const foreignKey = `${inflection.singularize(name)}Id`;
Object.entries(db.data).forEach(([key, items]) => {
// Skip
if (key === name || !dependents.includes(key))
return;
// Delete if foreign key is null
if (Array.isArray(items)) {
db.data[key] = items.filter((item) => item[foreignKey] !== null);
}
});
}
function randomId() {
return randomBytes(2).toString('hex');
}
function fixItemsIds(items) {
items.forEach((item) => {
if (typeof item['id'] === 'number') {
item['id'] = item['id'].toString();
}
if (item['id'] === undefined) {
item['id'] = randomId();
}
});
}
// Ensure all items have an id
function fixAllItemsIds(data) {
Object.values(data).forEach((value) => {
if (Array.isArray(value)) {
fixItemsIds(value);
}
});
}
export class Service {
#db;
constructor(db) {
fixAllItemsIds(db.data);
this.#db = db;
}
#get(name) {
return this.#db.data[name];
}
has(name) {
return Object.prototype.hasOwnProperty.call(this.#db?.data, name);
}
findById(name, id, query) {
const value = this.#get(name);
if (Array.isArray(value)) {
let item = value.find((item) => item['id'] === id);
ensureArray(query._embed).forEach((related) => {
if (item !== undefined)
item = embed(this.#db, name, item, related);
});
return item;
}
return;
}
find(name, query = {}) {
let items = this.#get(name);
if (!Array.isArray(items)) {
return items;
}
// Include
ensureArray(query._embed).forEach((related) => {
if (items !== undefined && Array.isArray(items)) {
items = items.map((item) => embed(this.#db, name, item, related));
}
});
// Return list if no query params
if (Object.keys(query).length === 0) {
return items;
}
// Convert query params to conditions
const conds = [];
for (const [key, value] of Object.entries(query)) {
if (value === undefined || typeof value !== 'string') {
continue;
}
const re = /_(lt|lte|gt|gte|ne)$/;
const reArr = re.exec(key);
const op = reArr?.at(1);
if (op && isCondition(op)) {
const field = key.replace(re, '');
conds.push([field, op, value]);
continue;
}
if ([
'_embed',
'_sort',
'_start',
'_end',
'_limit',
'_page',
'_per_page',
].includes(key)) {
continue;
}
conds.push([key, Condition.default, value]);
}
// Loop through conditions and filter items
let filtered = items;
for (const [key, op, paramValue] of conds) {
filtered = filtered.filter((item) => {
if (paramValue && !Array.isArray(paramValue)) {
// https://github.com/sindresorhus/dot-prop/issues/95
const itemValue = getProperty(item, key);
switch (op) {
// item_gt=value
case Condition.gt: {
if (!(typeof itemValue === 'number' &&
itemValue > parseInt(paramValue))) {
return false;
}
break;
}
// item_gte=value
case Condition.gte: {
if (!(typeof itemValue === 'number' &&
itemValue >= parseInt(paramValue))) {
return false;
}
break;
}
// item_lt=value
case Condition.lt: {
if (!(typeof itemValue === 'number' &&
itemValue < parseInt(paramValue))) {
return false;
}
break;
}
// item_lte=value
case Condition.lte: {
if (!(typeof itemValue === 'number' &&
itemValue <= parseInt(paramValue))) {
return false;
}
break;
}
// item_ne=value
case Condition.ne: {
switch (typeof itemValue) {
case 'number':
return itemValue !== parseInt(paramValue);
case 'string':
return itemValue !== paramValue;
case 'boolean':
return itemValue !== (paramValue === 'true');
}
break;
}
// item=value
case Condition.default: {
switch (typeof itemValue) {
case 'number':
return itemValue === parseInt(paramValue);
case 'string':
return itemValue === paramValue;
case 'boolean':
return itemValue === (paramValue === 'true');
}
}
}
}
return true;
});
}
// Sort
const sort = query._sort || '';
const sorted = sortOn(filtered, sort.split(','));
// Slice
const start = query._start;
const end = query._end;
const limit = query._limit;
if (start !== undefined) {
if (end !== undefined) {
return sorted.slice(start, end);
}
return sorted.slice(start, start + (limit || 0));
}
if (limit !== undefined) {
return sorted.slice(0, limit);
}
// Paginate
let page = query._page;
const perPage = query._per_page || 10;
if (page) {
const items = sorted.length;
const pages = Math.ceil(items / perPage);
// Ensure page is within the valid range
page = Math.max(1, Math.min(page, pages));
const first = 1;
const prev = page > 1 ? page - 1 : null;
const next = page < pages ? page + 1 : null;
const last = pages;
const start = (page - 1) * perPage;
const end = start + perPage;
const data = sorted.slice(start, end);
return {
first,
prev,
next,
last,
pages,
items,
data,
};
}
return sorted.slice(start, end);
}
async create(name, data = {}) {
const items = this.#get(name);
if (items === undefined || !Array.isArray(items))
return;
const item = { id: randomId(), ...data };
items.push(item);
await this.#db.write();
return item;
}
async #updateOrPatch(name, body = {}, isPatch) {
const item = this.#get(name);
if (item === undefined || Array.isArray(item))
return;
const nextItem = (this.#db.data[name] = isPatch ? { item, ...body } : body);
await this.#db.write();
return nextItem;
}
async #updateOrPatchById(name, id, body = {}, isPatch) {
const items = this.#get(name);
if (items === undefined || !Array.isArray(items))
return;
const item = items.find((item) => item['id'] === id);
if (!item)
return;
const nextItem = isPatch ? { ...item, ...body, id } : { ...body, id };
const index = items.indexOf(item);
items.splice(index, 1, nextItem);
await this.#db.write();
return nextItem;
}
async update(name, body = {}) {
return this.#updateOrPatch(name, body, false);
}
async patch(name, body = {}) {
return this.#updateOrPatch(name, body, true);
}
async updateById(name, id, body = {}) {
return this.#updateOrPatchById(name, id, body, false);
}
async patchById(name, id, body = {}) {
return this.#updateOrPatchById(name, id, body, true);
}
async destroyById(name, id, dependent) {
const items = this.#get(name);
if (items === undefined || !Array.isArray(items))
return;
const item = items.find((item) => item['id'] === id);
if (item === undefined)
return;
const index = items.indexOf(item);
items.splice(index, 1);
nullifyForeignKey(this.#db, name, id);
const dependents = ensureArray(dependent);
deleteDependents(this.#db, name, dependents);
await this.#db.write();
return item;
}
}