mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-18 23:44:12 +01:00
Run oxfmt across repo, add format script and docs
Add .oxfmtignore to skip generated bindings and wasm-pack output. Add npm format script, update DEVELOPMENT.md for Vite+ toolchain, and format all non-generated files with oxfmt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "@yaak/template-function-timestamp",
|
||||
"displayName": "Timestamp Template Functions",
|
||||
"description": "Template functions for dealing with timestamps",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"description": "Template functions for dealing with timestamps",
|
||||
"scripts": {
|
||||
"build": "yaakcli build",
|
||||
"dev": "yaakcli dev",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { PluginDefinition } from '@yaakapp/api';
|
||||
import type { TemplateFunctionArg } from '@yaakapp-internal/plugins';
|
||||
import type { PluginDefinition } from "@yaakapp/api";
|
||||
import type { TemplateFunctionArg } from "@yaakapp-internal/plugins";
|
||||
|
||||
import type { ContextFn } from 'date-fns';
|
||||
import type { ContextFn } from "date-fns";
|
||||
import {
|
||||
addDays,
|
||||
addHours,
|
||||
@@ -18,75 +18,75 @@ import {
|
||||
subMonths,
|
||||
subSeconds,
|
||||
subYears,
|
||||
} from 'date-fns';
|
||||
} from "date-fns";
|
||||
|
||||
const dateArg: TemplateFunctionArg = {
|
||||
type: 'text',
|
||||
name: 'date',
|
||||
label: 'Timestamp',
|
||||
type: "text",
|
||||
name: "date",
|
||||
label: "Timestamp",
|
||||
optional: true,
|
||||
description:
|
||||
'Can be a timestamp in milliseconds, ISO string, or anything parseable by JS `new Date()`',
|
||||
"Can be a timestamp in milliseconds, ISO string, or anything parseable by JS `new Date()`",
|
||||
placeholder: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const expressionArg: TemplateFunctionArg = {
|
||||
type: 'text',
|
||||
name: 'expression',
|
||||
label: 'Expression',
|
||||
type: "text",
|
||||
name: "expression",
|
||||
label: "Expression",
|
||||
description: "Modification expression (eg. '-5d +2h 3m'). Available units: y, M, d, h, m, s",
|
||||
optional: true,
|
||||
placeholder: '-5d +2h 3m',
|
||||
placeholder: "-5d +2h 3m",
|
||||
};
|
||||
|
||||
const formatArg: TemplateFunctionArg = {
|
||||
name: 'format',
|
||||
label: 'Format String',
|
||||
name: "format",
|
||||
label: "Format String",
|
||||
description: "Format string to describe the output (eg. 'yyyy-MM-dd at HH:mm:ss')",
|
||||
optional: true,
|
||||
placeholder: 'yyyy-MM-dd HH:mm:ss',
|
||||
type: 'text',
|
||||
placeholder: "yyyy-MM-dd HH:mm:ss",
|
||||
type: "text",
|
||||
};
|
||||
|
||||
export const plugin: PluginDefinition = {
|
||||
templateFunctions: [
|
||||
{
|
||||
name: 'timestamp.unix',
|
||||
description: 'Get the timestamp in seconds',
|
||||
name: "timestamp.unix",
|
||||
description: "Get the timestamp in seconds",
|
||||
args: [dateArg],
|
||||
onRender: async (_ctx, args) => {
|
||||
const d = parseDateString(String(args.values.date ?? ''));
|
||||
const d = parseDateString(String(args.values.date ?? ""));
|
||||
return String(Math.floor(d.getTime() / 1000));
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'timestamp.unixMillis',
|
||||
description: 'Get the timestamp in milliseconds',
|
||||
name: "timestamp.unixMillis",
|
||||
description: "Get the timestamp in milliseconds",
|
||||
args: [dateArg],
|
||||
onRender: async (_ctx, args) => {
|
||||
const d = parseDateString(String(args.values.date ?? ''));
|
||||
const d = parseDateString(String(args.values.date ?? ""));
|
||||
return String(d.getTime());
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'timestamp.iso8601',
|
||||
description: 'Get the date in ISO8601 format',
|
||||
name: "timestamp.iso8601",
|
||||
description: "Get the date in ISO8601 format",
|
||||
args: [dateArg],
|
||||
onRender: async (_ctx, args) => {
|
||||
const d = parseDateString(String(args.values.date ?? ''));
|
||||
const d = parseDateString(String(args.values.date ?? ""));
|
||||
return d.toISOString();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'timestamp.format',
|
||||
description: 'Format a date using a dayjs-compatible format string',
|
||||
name: "timestamp.format",
|
||||
description: "Format a date using a dayjs-compatible format string",
|
||||
args: [dateArg, formatArg],
|
||||
previewArgs: [formatArg.name],
|
||||
onRender: async (_ctx, args) => formatDatetime(args.values),
|
||||
},
|
||||
{
|
||||
name: 'timestamp.offset',
|
||||
description: 'Get the offset of a date based on an expression',
|
||||
name: "timestamp.offset",
|
||||
description: "Get the offset of a date based on an expression",
|
||||
args: [dateArg, expressionArg],
|
||||
previewArgs: [expressionArg.name],
|
||||
onRender: async (_ctx, args) => calculateDatetime(args.values),
|
||||
@@ -96,18 +96,18 @@ export const plugin: PluginDefinition = {
|
||||
|
||||
function applyDateOp(d: Date, sign: string, amount: number, unit: string): Date {
|
||||
switch (unit) {
|
||||
case 'y':
|
||||
return sign === '-' ? subYears(d, amount) : addYears(d, amount);
|
||||
case 'M':
|
||||
return sign === '-' ? subMonths(d, amount) : addMonths(d, amount);
|
||||
case 'd':
|
||||
return sign === '-' ? subDays(d, amount) : addDays(d, amount);
|
||||
case 'h':
|
||||
return sign === '-' ? subHours(d, amount) : addHours(d, amount);
|
||||
case 'm':
|
||||
return sign === '-' ? subMinutes(d, amount) : addMinutes(d, amount);
|
||||
case 's':
|
||||
return sign === '-' ? subSeconds(d, amount) : addSeconds(d, amount);
|
||||
case "y":
|
||||
return sign === "-" ? subYears(d, amount) : addYears(d, amount);
|
||||
case "M":
|
||||
return sign === "-" ? subMonths(d, amount) : addMonths(d, amount);
|
||||
case "d":
|
||||
return sign === "-" ? subDays(d, amount) : addDays(d, amount);
|
||||
case "h":
|
||||
return sign === "-" ? subHours(d, amount) : addHours(d, amount);
|
||||
case "m":
|
||||
return sign === "-" ? subMinutes(d, amount) : addMinutes(d, amount);
|
||||
case "s":
|
||||
return sign === "-" ? subSeconds(d, amount) : addSeconds(d, amount);
|
||||
default:
|
||||
throw new Error(`Invalid data calculation unit: ${unit}`);
|
||||
}
|
||||
@@ -120,7 +120,7 @@ function parseOp(op: string): { sign: string; amount: number; unit: string } | n
|
||||
}
|
||||
const [, sign, amount, unit] = match;
|
||||
if (!unit) return null;
|
||||
return { sign: sign ?? '+', amount: Number(amount ?? 0), unit };
|
||||
return { sign: sign ?? "+", amount: Number(amount ?? 0), unit };
|
||||
}
|
||||
|
||||
function parseDateString(date: string): Date {
|
||||
@@ -143,11 +143,11 @@ function parseDateString(date: string): Date {
|
||||
|
||||
export function calculateDatetime(args: { date?: string; expression?: string }): string {
|
||||
const { date, expression } = args;
|
||||
let jsDate = parseDateString(date ?? '');
|
||||
let jsDate = parseDateString(date ?? "");
|
||||
|
||||
if (expression) {
|
||||
const ops = String(expression)
|
||||
.split(' ')
|
||||
.split(" ")
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
for (const op of ops) {
|
||||
@@ -167,6 +167,6 @@ export function formatDatetime(args: {
|
||||
in?: ContextFn<Date>;
|
||||
}): string {
|
||||
const { date, format } = args;
|
||||
const d = parseDateString(date ?? '');
|
||||
return formatDate(d, String(format || 'yyyy-MM-dd HH:mm:ss'), { in: args.in });
|
||||
const d = parseDateString(date ?? "");
|
||||
return formatDate(d, String(format || "yyyy-MM-dd HH:mm:ss"), { in: args.in });
|
||||
}
|
||||
|
||||
@@ -1,72 +1,72 @@
|
||||
import { tz } from '@date-fns/tz';
|
||||
import { describe, expect, it } from 'vite-plus/test';
|
||||
import { calculateDatetime, formatDatetime } from '../src';
|
||||
import { tz } from "@date-fns/tz";
|
||||
import { describe, expect, it } from "vite-plus/test";
|
||||
import { calculateDatetime, formatDatetime } from "../src";
|
||||
|
||||
describe('formatDatetime', () => {
|
||||
it('returns formatted current date', () => {
|
||||
describe("formatDatetime", () => {
|
||||
it("returns formatted current date", () => {
|
||||
const result = formatDatetime({});
|
||||
expect(result).toMatch(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/);
|
||||
});
|
||||
|
||||
it('returns formatted specific date', () => {
|
||||
const result = formatDatetime({ date: '2025-07-13T12:34:56' });
|
||||
expect(result).toBe('2025-07-13 12:34:56');
|
||||
it("returns formatted specific date", () => {
|
||||
const result = formatDatetime({ date: "2025-07-13T12:34:56" });
|
||||
expect(result).toBe("2025-07-13 12:34:56");
|
||||
});
|
||||
|
||||
it('returns formatted specific timestamp', () => {
|
||||
const result = formatDatetime({ date: '1752435296000', in: tz('America/Vancouver') });
|
||||
expect(result).toBe('2025-07-13 12:34:56');
|
||||
it("returns formatted specific timestamp", () => {
|
||||
const result = formatDatetime({ date: "1752435296000", in: tz("America/Vancouver") });
|
||||
expect(result).toBe("2025-07-13 12:34:56");
|
||||
});
|
||||
|
||||
it('returns formatted specific timestamp with decimals', () => {
|
||||
const result = formatDatetime({ date: '1752435296000.19', in: tz('America/Vancouver') });
|
||||
expect(result).toBe('2025-07-13 12:34:56');
|
||||
it("returns formatted specific timestamp with decimals", () => {
|
||||
const result = formatDatetime({ date: "1752435296000.19", in: tz("America/Vancouver") });
|
||||
expect(result).toBe("2025-07-13 12:34:56");
|
||||
});
|
||||
|
||||
it('returns formatted date with custom output', () => {
|
||||
const result = formatDatetime({ date: '2025-07-13T12:34:56', format: 'dd/MM/yyyy' });
|
||||
expect(result).toBe('13/07/2025');
|
||||
it("returns formatted date with custom output", () => {
|
||||
const result = formatDatetime({ date: "2025-07-13T12:34:56", format: "dd/MM/yyyy" });
|
||||
expect(result).toBe("13/07/2025");
|
||||
});
|
||||
|
||||
it('handles invalid date gracefully', () => {
|
||||
expect(() => formatDatetime({ date: 'invalid-date' })).toThrow('Invalid date: invalid-date');
|
||||
it("handles invalid date gracefully", () => {
|
||||
expect(() => formatDatetime({ date: "invalid-date" })).toThrow("Invalid date: invalid-date");
|
||||
});
|
||||
});
|
||||
|
||||
describe('calculateDatetime', () => {
|
||||
it('returns ISO string for current date', () => {
|
||||
describe("calculateDatetime", () => {
|
||||
it("returns ISO string for current date", () => {
|
||||
const result = calculateDatetime({});
|
||||
expect(result).toMatch(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/);
|
||||
});
|
||||
|
||||
it('returns ISO string for specific date', () => {
|
||||
const result = calculateDatetime({ date: '2025-07-13T12:34:56Z' });
|
||||
expect(result).toBe('2025-07-13T12:34:56.000Z');
|
||||
it("returns ISO string for specific date", () => {
|
||||
const result = calculateDatetime({ date: "2025-07-13T12:34:56Z" });
|
||||
expect(result).toBe("2025-07-13T12:34:56.000Z");
|
||||
});
|
||||
|
||||
it('applies calc operations', () => {
|
||||
const result = calculateDatetime({ date: '2025-07-13T12:00:00Z', expression: '+1d 2h' });
|
||||
expect(result).toBe('2025-07-14T14:00:00.000Z');
|
||||
it("applies calc operations", () => {
|
||||
const result = calculateDatetime({ date: "2025-07-13T12:00:00Z", expression: "+1d 2h" });
|
||||
expect(result).toBe("2025-07-14T14:00:00.000Z");
|
||||
});
|
||||
|
||||
it('applies negative calc operations', () => {
|
||||
const result = calculateDatetime({ date: '2025-07-13T12:00:00Z', expression: '-1d -2h 1m' });
|
||||
expect(result).toBe('2025-07-12T10:01:00.000Z');
|
||||
it("applies negative calc operations", () => {
|
||||
const result = calculateDatetime({ date: "2025-07-13T12:00:00Z", expression: "-1d -2h 1m" });
|
||||
expect(result).toBe("2025-07-12T10:01:00.000Z");
|
||||
});
|
||||
|
||||
it('throws error for invalid unit', () => {
|
||||
expect(() => calculateDatetime({ date: '2025-07-13T12:00:00Z', expression: '+1x' })).toThrow(
|
||||
'Invalid date expression: +1x',
|
||||
it("throws error for invalid unit", () => {
|
||||
expect(() => calculateDatetime({ date: "2025-07-13T12:00:00Z", expression: "+1x" })).toThrow(
|
||||
"Invalid date expression: +1x",
|
||||
);
|
||||
});
|
||||
it('throws error for invalid unit weird', () => {
|
||||
expect(() => calculateDatetime({ date: '2025-07-13T12:00:00Z', expression: '+1&#^%' })).toThrow(
|
||||
'Invalid date expression: +1&#^%',
|
||||
it("throws error for invalid unit weird", () => {
|
||||
expect(() => calculateDatetime({ date: "2025-07-13T12:00:00Z", expression: "+1&#^%" })).toThrow(
|
||||
"Invalid date expression: +1&#^%",
|
||||
);
|
||||
});
|
||||
it('throws error for bad expression', () => {
|
||||
it("throws error for bad expression", () => {
|
||||
expect(() =>
|
||||
calculateDatetime({ date: '2025-07-13T12:00:00Z', expression: 'bad expr' }),
|
||||
).toThrow('Invalid date expression: bad');
|
||||
calculateDatetime({ date: "2025-07-13T12:00:00Z", expression: "bad expr" }),
|
||||
).toThrow("Invalid date expression: bad");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user