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

44
25_02_24/node_modules/json-server/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,44 @@
Fair Source License, version 0.9
Copyright (C) 2023-present typicode
Licensor: typicode
Software: json-server
Use Limitation: 2 users
License Grant. Licensor hereby grants to each recipient of the
Software ("you") a non-exclusive, non-transferable, royalty-free and
fully-paid-up license, under all of the Licensor's copyright and
patent rights, to use, copy, distribute, prepare derivative works of,
publicly perform and display the Software, subject to the Use
Limitation and the conditions set forth below.
Use Limitation. The license granted above allows use by up to the
number of users per entity set forth above (the "Use Limitation"). For
determining the number of users, "you" includes all affiliates,
meaning legal entities controlling, controlled by, or under common
control with you. If you exceed the Use Limitation, your use is
subject to payment of Licensor's then-current list price for licenses.
Conditions. Redistribution in source code or other forms must include
a copy of this license document to be provided in a reasonable
manner. Any redistribution of the Software is only allowed subject to
this license.
Trademarks. This license does not grant you any right in the
trademarks, service marks, brand names or logos of Licensor.
DISCLAIMER. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OR
CONDITION, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. LICENSORS HEREBY DISCLAIM ALL LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE.
Termination. If you violate the terms of this license, your rights
will terminate automatically and will not be reinstated without the
prior written consent of Licensor. Any such termination will not
affect the right of others who may have received copies of the
Software from you.

209
25_02_24/node_modules/json-server/README.md generated vendored Normal file
View File

@@ -0,0 +1,209 @@
# json-server
[![Node.js CI](https://github.com/typicode/json-server/actions/workflows/node.js.yml/badge.svg)](https://github.com/typicode/json-server/actions/workflows/node.js.yml)
> [!IMPORTANT]
> Viewing beta v1 documentation usable but expect breaking changes. For stable version, see [here](https://github.com/typicode/json-server/tree/v0)
👋 _Hey! Using React, Vue or Astro? Check my new project [MistCSS](https://github.com/typicode/mistcss) to write 50% less code._
## Install
```shell
npm install json-server
```
## Usage
Create a `db.json` or `db.json5` file
```json
{
"posts": [
{ "id": "1", "title": "a title", "views": 100 },
{ "id": "2", "title": "another title", "views": 200 }
],
"comments": [
{ "id": "1", "text": "a comment about post 1", "postId": "1" },
{ "id": "2", "text": "another comment about post 1", "postId": "1" }
],
"profile": {
"name": "typicode"
}
}
```
<details>
<summary>View db.json5 example</summary>
```json5
{
posts: [
{ id: '1', title: 'a title', views: 100 },
{ id: '2', title: 'another title', views: 200 },
],
comments: [
{ id: '1', text: 'a comment about post 1', postId: '1' },
{ id: '2', text: 'another comment about post 1', postId: '1' },
],
profile: {
name: 'typicode',
},
}
```
You can read more about JSON5 format [here](https://github.com/json5/json5).
</details>
Pass it to JSON Server CLI
```shell
$ npx json-server db.json
```
Get a REST API
```shell
$ curl http://localhost:3000/posts/1
{
"id": "1",
"title": "a title",
"views": 100
}
```
Run `json-server --help` for a list of options
## Sponsors ✨
| Sponsors |
| :---: |
| <a href="https://mockend.com/" target="_blank"><img src="https://jsonplaceholder.typicode.com/mockend.svg" height="100px"></a> |
| <a href="https://zuplo.link/json-server-gh"><img src="https://github.com/typicode/json-server/assets/5502029/928b7526-0fdf-46ae-80d9-27fa0ef5f430"></a> |
| Sponsors |
| :---: |
| <a href="https://konghq.com/products/kong-konnect?utm_medium=referral&utm_source=github&utm_campaign=platform&utm_content=json-server"><img src="https://github.com/typicode/json-server/assets/5502029/e8d8ecb2-3c45-4f60-92d0-a060b820fa7f" height="75px"></a> |
| Sponsors | |
| :---: | :---: |
| <a href="https://www.storyblok.com/" target="_blank"><img src="https://github.com/typicode/json-server/assets/5502029/c6b10674-4ada-4616-91b8-59d30046b45a" height="35px"></a> | <a href="https://betterstack.com/" target="_blank"><img src="https://github.com/typicode/json-server/assets/5502029/44679f8f-9671-470d-b77e-26d90b90cbdc" height="35px"></a> |
| <a href="https://route4me.com"><img src="https://github.com/user-attachments/assets/4eab0bac-119e-4b27-8183-8b136190b776" height="35px" alt="Delivery Routing Software and Route Optimization Software"></a> | <a href="https://www.speechanddebate.org"><img src="https://github.com/user-attachments/assets/cc7980e4-2147-4499-8de4-4d0c265d0c07" height="35px"></a> |
[Become a sponsor and have your company logo here](https://github.com/users/typicode/sponsorship)
## Sponsorware
> [!NOTE]
> This project uses the [Fair Source License](https://fair.io/). Only organizations with 3+ users are kindly asked to contribute a small amount through sponsorship [sponsor](https://github.com/sponsors/typicode) for usage. __This license helps keep the project sustainable and healthy, benefiting everyone.__
>
> For more information, FAQs, and the rationale behind this, visit [https://fair.io/](https://fair.io/).
## Routes
Based on the example `db.json`, you'll get the following routes:
```
GET /posts
GET /posts/:id
POST /posts
PUT /posts/:id
PATCH /posts/:id
DELETE /posts/:id
# Same for comments
```
```
GET /profile
PUT /profile
PATCH /profile
```
## Params
### Conditions
- ` ``==`
- `lt``<`
- `lte``<=`
- `gt``>`
- `gte``>=`
- `ne``!=`
```
GET /posts?views_gt=9000
```
### Range
- `start`
- `end`
- `limit`
```
GET /posts?_start=10&_end=20
GET /posts?_start=10&_limit=10
```
### Paginate
- `page`
- `per_page` (default = 10)
```
GET /posts?_page=1&_per_page=25
```
### Sort
- `_sort=f1,f2`
```
GET /posts?_sort=id,-views
```
### Nested and array fields
- `x.y.z...`
- `x.y.z[i]...`
```
GET /foo?a.b=bar
GET /foo?x.y_lt=100
GET /foo?arr[0]=bar
```
### Embed
```
GET /posts?_embed=comments
GET /comments?_embed=post
```
## Delete
```
DELETE /posts/1
DELETE /posts/1?_dependent=comments
```
## Serving static files
If you create a `./public` directory, JSON Server will serve its content in addition to the REST API.
You can also add custom directories using `-s/--static` option.
```sh
json-server -s ./static
json-server -s ./static -s ./node_modules
```
## Notable differences with v0.17
- `id` is always a string and will be generated for you if missing
- use `_per_page` with `_page` instead of `_limit`for pagination
- use Chrome's `Network tab > throtling` to delay requests instead of `--delay` CLI option

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;
}
}

63
25_02_24/node_modules/json-server/package.json generated vendored Normal file
View File

@@ -0,0 +1,63 @@
{
"name": "json-server",
"version": "1.0.0-beta.3",
"description": "",
"type": "module",
"bin": {
"json-server": "lib/bin.js"
},
"types": "lib",
"files": [
"lib",
"views"
],
"engines": {
"node": ">=18.3"
},
"scripts": {
"dev": "tsx watch src/bin.ts fixtures/db.json",
"build": "rm -rf lib && tsc",
"test": "node --import tsx/esm --test src/*.test.ts",
"lint": "eslint src",
"prepare": "husky",
"prepublishOnly": "npm run build"
},
"keywords": [],
"author": "typicode <typicode@gmail.com>",
"license": "SEE LICENSE IN ./LICENSE",
"repository": {
"type": "git",
"url": "git+https://github.com/typicode/json-server.git"
},
"devDependencies": {
"@eslint/js": "^9.11.0",
"@sindresorhus/tsconfig": "^6.0.0",
"@tailwindcss/typography": "^0.5.15",
"@types/node": "^22.5.5",
"concurrently": "^9.0.1",
"eslint": "^9.11.0",
"get-port": "^7.1.0",
"globals": "^15.9.0",
"husky": "^9.1.6",
"tempy": "^3.1.0",
"tsx": "^4.19.1",
"type-fest": "^4.26.1",
"typescript": "^5.6.2",
"typescript-eslint": "^8.6.0"
},
"dependencies": {
"@tinyhttp/app": "^2.4.0",
"@tinyhttp/cors": "^2.0.1",
"@tinyhttp/logger": "^2.0.0",
"chalk": "^5.3.0",
"chokidar": "^4.0.1",
"dot-prop": "^9.0.0",
"eta": "^3.5.0",
"inflection": "^3.0.0",
"json5": "^2.2.3",
"lowdb": "^7.0.1",
"milliparsec": "^4.0.0",
"sirv": "^2.0.4",
"sort-on": "^6.1.0"
}
}

97
25_02_24/node_modules/json-server/views/index.html generated vendored Normal file
View File

@@ -0,0 +1,97 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
html {
font-size: 16px;
line-height: 1.5;
background-color: #fff;
color: #000;
}
body {
margin: 0 auto;
max-width: 720px;
padding: 0 16px;
font-family: sans-serif;
}
a {
color: #db2777;
text-decoration: none;
}
header {
margin-bottom: 32px;
padding: 16px 0;
}
nav {
display: flex;
justify-content: space-between;
}
nav div a {
margin-left: 16px;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
margin-bottom: 8px;
}
/* Dark mode styles */
@media (prefers-color-scheme: dark) {
html {
background-color: #1e293b;
color: #fff;
}
a {
}
}
</style>
</head>
<body>
<header>
<nav>
<strong>JSON Server</strong>
<div>
<a href="https://github.com/typicode/json-server">Docs</a>
<a href="https://github.com/sponsors/typicode">♡ Sponsor</a>
</div>
</nav>
</header>
<main class="my-12">
<p class="bg-gradient-to-r from-purple-500 via-pink-500 to-red-500 text-transparent bg-clip-text">✧*。٩(ˊᗜˋ*)و✧*。</p>
<% if (Object.keys(it.data).length===0) { %>
<p>No resources found in JSON file</p>
<% } %>
<% Object.entries(it.data).forEach(function([name]) { %>
<ul>
<li>
<a href="<%= name %>">/<%= name %></a>
<span>
<% if (Array.isArray(it.data[name])) { %>
- <%= it.data[name].length %>
<%= it.data[name].length> 1 ? 'items' : 'item' %>
</span>
<% } %>
</li>
</ul>
<% }) %>
</main>
</body>
</html>