@autobusal/utilities 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -21
- package/check-backticks.mjs +91 -0
- package/date.tsx +22 -0
- package/index.ts +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,30 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## [1.2.0] - 2026-07-25
|
|
6
|
-
|
|
7
|
-
### Added
|
|
8
|
-
|
|
9
|
-
- `GetChannelStatus(t)`: shared disabled/dedicated/main select values for
|
|
10
|
-
the Telegram and WhatsApp admin settings tabs (and any future per-label
|
|
11
|
-
messaging channel).
|
|
12
|
-
|
|
13
|
-
## [1.1.2] - 2026-07-24
|
|
3
|
+
## 1.4.0
|
|
14
4
|
|
|
15
5
|
### Added
|
|
16
6
|
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
## [1.1.1] - 2026-07-19
|
|
20
|
-
|
|
21
|
-
### Added
|
|
7
|
+
- **`check-backticks.mjs`**, moved here from the autobusal repo root so the
|
|
8
|
+
apps can run it too.
|
|
22
9
|
|
|
23
|
-
|
|
24
|
-
|
|
10
|
+
A backtick used as quoting inside a styled-components template *terminates
|
|
11
|
+
the template*. The bundler then reports a syntax error somewhere further
|
|
12
|
+
down, pointing at a line that is perfectly fine — so the search starts in
|
|
13
|
+
the wrong place every time. Per the script's own history that cost five
|
|
14
|
+
build failures in one session before anyone connected the two.
|
|
25
15
|
|
|
26
|
-
|
|
16
|
+
It only ever guarded `packages`, and the trap is not confined there: it bit
|
|
17
|
+
`magus/src` the moment a public page grew its own styled-components, with
|
|
18
|
+
nothing watching. Each app's `prebuild` now runs it over its own `src`
|
|
19
|
+
(first, so a broken template stops the build before it spends minutes
|
|
20
|
+
copying files), and `publish.sh` still runs it over `packages`.
|
|
27
21
|
|
|
28
|
-
|
|
22
|
+
One script with three callers, rather than a copy per repo that drifts.
|
|
29
23
|
|
|
30
|
-
|
|
24
|
+
Takes the directory to scan as its argument.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Refuse to publish a backtick used as quoting inside a styled-components
|
|
4
|
+
* template literal.
|
|
5
|
+
*
|
|
6
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
7
|
+
*
|
|
8
|
+
* A backtick inside a CSS comment TERMINATES the template string. What the
|
|
9
|
+
* bundler then reports is a syntax error somewhere further down, pointing at
|
|
10
|
+
* a line that is perfectly fine - so the search starts in the wrong place
|
|
11
|
+
* every time. It cost five build failures in a single session before anyone
|
|
12
|
+
* connected the two.
|
|
13
|
+
*
|
|
14
|
+
* TWO THINGS HERE ARE LEGITIMATE and must never be flagged, which is why
|
|
15
|
+
* this is not a plain grep:
|
|
16
|
+
*
|
|
17
|
+
* - nested css`...` interpolations, which this codebase uses everywhere
|
|
18
|
+
* - backticks in the JSDoc ABOVE a styled block, which are idiomatic and
|
|
19
|
+
* sit outside the template entirely
|
|
20
|
+
*
|
|
21
|
+
* The bug is only ever the intersection: a backtick inside a comment that
|
|
22
|
+
* sits BETWEEN styled.x` and its closing `;
|
|
23
|
+
*
|
|
24
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-06
|
|
25
|
+
* Moved into @autobusal/utilities from the repo root, so the APPS can run it
|
|
26
|
+
* too. It only ever guarded `packages`, and the trap is not confined there:
|
|
27
|
+
* it bit magus/src the moment a public page grew its own styled-components,
|
|
28
|
+
* with nothing watching. Each app's prebuild now runs it over its own src,
|
|
29
|
+
* and publish.sh still runs it over packages - one script, three callers,
|
|
30
|
+
* rather than a copy per repo that drifts.
|
|
31
|
+
*
|
|
32
|
+
* Takes the directory to scan as its argument.
|
|
33
|
+
*/
|
|
34
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
35
|
+
import { join } from 'node:path';
|
|
36
|
+
|
|
37
|
+
const OPEN = /styled(?:\.\w+|\([^)]*\))(?:<[^>]*>)?`/g;
|
|
38
|
+
|
|
39
|
+
const walk = (dir) => readdirSync(dir).flatMap((entry) => {
|
|
40
|
+
const path = join(dir, entry);
|
|
41
|
+
|
|
42
|
+
if (entry === 'node_modules' || entry.startsWith('.')) {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (statSync(path).isDirectory()) {
|
|
47
|
+
return walk(path);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return /\.tsx?$/.test(entry) ? [path] : [];
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const found = [];
|
|
54
|
+
|
|
55
|
+
for (const path of walk(process.argv[2] ?? 'packages')) {
|
|
56
|
+
const text = readFileSync(path, 'utf8');
|
|
57
|
+
|
|
58
|
+
for (const match of text.matchAll(OPEN)) {
|
|
59
|
+
const start = match.index + match[0].length;
|
|
60
|
+
const end = text.indexOf('`;', start);
|
|
61
|
+
|
|
62
|
+
if (end === -1) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const base = text.slice(0, start).split('\n').length;
|
|
67
|
+
let comment = false;
|
|
68
|
+
|
|
69
|
+
text.slice(start, end).split('\n').forEach((line, n) => {
|
|
70
|
+
if (line.includes('/*')) {
|
|
71
|
+
comment = true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (comment && line.includes('`')) {
|
|
75
|
+
found.push(`${ path }:${ base + n }: ${ line.trim().slice(0, 72) }`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (line.includes('*/')) {
|
|
79
|
+
comment = false;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (found.length > 0) {
|
|
86
|
+
console.error('Backtick in a comment inside a styled template - this breaks the build:');
|
|
87
|
+
found.forEach((line) => console.error(` ${ line }`));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.log('backticks: clean');
|
package/date.tsx
CHANGED
|
@@ -27,6 +27,28 @@ export const getFormattedShort = (date: Date, t: TFunction<'generate'>): string
|
|
|
27
27
|
return `${ t(display.weekday, { ns: 'common' }) }, ${ display.day } ${ t(display.month, { ns: 'common' }).substring(0, 3) }`;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* The same short date, but in parts.
|
|
32
|
+
*
|
|
33
|
+
* Edited: Ferjolt Ozuni - Date: 2026-08-03
|
|
34
|
+
*
|
|
35
|
+
* getFormattedShort returns one string, so a caller that needs to drop the
|
|
36
|
+
* month on a narrow screen cannot - CSS can hide an element but it cannot
|
|
37
|
+
* shorten a sentence. The seven-day strip needs exactly that: "Sat, 01 Aug"
|
|
38
|
+
* seven times does not fit a phone, "Sat 01" does.
|
|
39
|
+
*/
|
|
40
|
+
export const getDayParts = (date: Date, t: TFunction<'generate'>): { weekday: string, day: string, month: string } => {
|
|
41
|
+
const day = date.getDate();
|
|
42
|
+
const month = date.toLocaleString('default', { month: 'long' });
|
|
43
|
+
const weekday = date.toLocaleString('default', { weekday: 'short' });
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
weekday: t(`data.days.${ weekday.toLowerCase() }`, { ns: 'common' }),
|
|
47
|
+
day: day < 10 ? `0${ day }` : String(day),
|
|
48
|
+
month: t(`data.months.${ month.toLowerCase() }`, { ns: 'common' }).substring(0, 3)
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
30
52
|
export const differenceYears = (date: Date): number => {
|
|
31
53
|
const milliseconds = Date.now() - date.getTime();
|
|
32
54
|
|
package/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createDate, prepareDate, getFormattedShort, differenceYears, futureDate } from './date';
|
|
1
|
+
import { createDate, prepareDate, getFormattedShort, getDayParts, differenceYears, futureDate } from './date';
|
|
2
2
|
import { Validate, Display } from './form';
|
|
3
3
|
import { error, notify, success } from './notify';
|
|
4
4
|
import { getAllowed, getLanguages, getPayments } from './options';
|
|
@@ -18,6 +18,7 @@ export {
|
|
|
18
18
|
createDate,
|
|
19
19
|
prepareDate,
|
|
20
20
|
getFormattedShort,
|
|
21
|
+
getDayParts,
|
|
21
22
|
differenceYears,
|
|
22
23
|
DisplayStatus,
|
|
23
24
|
futureDate,
|