taglify 1.0.1
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/README.md +120 -0
- package/dist/index.cjs +81 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +38 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Taglify — keep generated content in sync, everywhere
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/taglify)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
[](./tsconfig.json)
|
|
6
|
+
[](https://github.com/jayf0x/taglify/actions/workflows/ci.yml)
|
|
7
|
+
|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
> ⭐ **Star this [repository](https://github.com/jayf0x/taglify) if you’d like to support its growth.**
|
|
11
|
+
|
|
12
|
+
I was writing bash functions to have my e2e tests output live stats in the
|
|
13
|
+
README of [compress-shader-literals](https://github.com/jayf0x/compress-shader-literals).
|
|
14
|
+
Then I started reaching for the same trick in other tools and thought "why not ship this".
|
|
15
|
+
Enjoy 🤗
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bun add taglify
|
|
21
|
+
# OR npm / pnpm / yarn ...
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Example
|
|
25
|
+
|
|
26
|
+
In your README:
|
|
27
|
+
|
|
28
|
+
```md
|
|
29
|
+
<!-- STATS:START -->
|
|
30
|
+
<!-- STATS:END -->
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
You build or release flow:
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
// scripts/sync-readme.js
|
|
37
|
+
import { taglifyFile } from 'taglify';
|
|
38
|
+
|
|
39
|
+
const coverageSummary = '...';
|
|
40
|
+
taglifyFile('./README.md', { STATS: coverageSummary });
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
// package.json
|
|
45
|
+
{
|
|
46
|
+
"scripts": {
|
|
47
|
+
"prepublishOnly": "bun run scripts/sync-readme.js"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
result:
|
|
53
|
+
|
|
54
|
+
```md
|
|
55
|
+
| Browser | Passed | Failed |
|
|
56
|
+
| ------- | ------ | ------ |
|
|
57
|
+
| Brave | 127 | 0 |
|
|
58
|
+
| Firefox | 127 | 0 |
|
|
59
|
+
| Edge | 0 | 127 |
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
Same idea works in a CI step, a git pre-commit hook, or a cron job.
|
|
65
|
+
|
|
66
|
+
## API
|
|
67
|
+
|
|
68
|
+
### `taglifyText(text, tags)`
|
|
69
|
+
|
|
70
|
+
| Param | Type | Description |
|
|
71
|
+
| ------ | ------------------------ | ------------------------------ |
|
|
72
|
+
| `text` | `string` | Source text |
|
|
73
|
+
| `tags` | `Record<string, string>` | Tag name → replacement content |
|
|
74
|
+
|
|
75
|
+
Returns `{ text: string, changed: boolean }`.
|
|
76
|
+
|
|
77
|
+
### `taglifyFile(filePath, tags)`
|
|
78
|
+
|
|
79
|
+
Reads `filePath`, applies `taglifyText`, and writes back only if the content
|
|
80
|
+
changed.
|
|
81
|
+
|
|
82
|
+
- Returns `boolean` — whether the file was modified.
|
|
83
|
+
- Throws a friendly error (`File not found: <path>`) if the file doesn't
|
|
84
|
+
exist.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Marker format
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<!-- TAG:START -->
|
|
92
|
+
content
|
|
93
|
+
<!-- TAG:END -->
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
| Rule | Behavior |
|
|
97
|
+
| -------------------------- | ----------------------------------------- |
|
|
98
|
+
| Tag name casing | Case-insensitive, normalized to uppercase |
|
|
99
|
+
| Content between markers | Fully replaced |
|
|
100
|
+
| Markers themselves | Always preserved |
|
|
101
|
+
| Multiple blocks, same tag | All replaced |
|
|
102
|
+
| Tag with no matching block | Skipped |
|
|
103
|
+
| Replacement value type | `string` only |
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Roadmap
|
|
108
|
+
|
|
109
|
+
Taglify is a small, deliberately minimal util today. These are ideas for
|
|
110
|
+
where it could go — see [BACKLOG.md](./BACKLOG.md) for the full list.
|
|
111
|
+
|
|
112
|
+
- [ ] Configurable marker syntax and comment styles (`//`, `#`, `/* */`)
|
|
113
|
+
- [ ] Create missing blocks instead of skipping
|
|
114
|
+
- [ ] CLI with dry-run and diff output
|
|
115
|
+
- [ ] Glob / directory processing
|
|
116
|
+
- [ ] Support non-string values, serialized as formatted JSON
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
[MIT](./LICENSE) © [jayF0x](https://github.com/jayf0x)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
8
|
+
var __toCommonJS = (from) => {
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
10
|
+
if (entry)
|
|
11
|
+
return entry;
|
|
12
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
__moduleCache.set(from, entry);
|
|
22
|
+
return entry;
|
|
23
|
+
};
|
|
24
|
+
var __moduleCache;
|
|
25
|
+
var __returnValue = (v) => v;
|
|
26
|
+
function __exportSetter(name, newValue) {
|
|
27
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
28
|
+
}
|
|
29
|
+
var __export = (target, all) => {
|
|
30
|
+
for (var name in all)
|
|
31
|
+
__defProp(target, name, {
|
|
32
|
+
get: all[name],
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
set: __exportSetter.bind(all, name)
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/index.ts
|
|
40
|
+
var exports_src = {};
|
|
41
|
+
__export(exports_src, {
|
|
42
|
+
taglifyText: () => taglifyText,
|
|
43
|
+
taglifyFile: () => taglifyFile
|
|
44
|
+
});
|
|
45
|
+
module.exports = __toCommonJS(exports_src);
|
|
46
|
+
var import_node_fs = require("node:fs");
|
|
47
|
+
var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
48
|
+
var taglifyText = (text, tags) => {
|
|
49
|
+
let output = text;
|
|
50
|
+
for (const [tagName, replacement] of Object.entries(tags)) {
|
|
51
|
+
const tag = escapeRegExp(tagName.toUpperCase());
|
|
52
|
+
const blockRegex = new RegExp(`<!-- ${tag}:START -->(.*?)<!-- ${tag}:END -->`, "gis");
|
|
53
|
+
output = output.replace(blockRegex, (_match, block) => {
|
|
54
|
+
const lineEnding = block.includes(`\r
|
|
55
|
+
`) ? `\r
|
|
56
|
+
` : `
|
|
57
|
+
`;
|
|
58
|
+
return `<!-- ${tag}:START -->${lineEnding}${replacement}${lineEnding}<!-- ${tag}:END -->`;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
text: output,
|
|
63
|
+
changed: output !== text
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
var taglifyFile = (filePath, tags) => {
|
|
67
|
+
let text;
|
|
68
|
+
try {
|
|
69
|
+
text = import_node_fs.readFileSync(filePath, "utf8");
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (error.code === "ENOENT") {
|
|
72
|
+
throw new Error(`File not found: ${filePath}`);
|
|
73
|
+
}
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
const result = taglifyText(text, tags);
|
|
77
|
+
if (result.changed) {
|
|
78
|
+
import_node_fs.writeFileSync(filePath, result.text, "utf8");
|
|
79
|
+
}
|
|
80
|
+
return result.changed;
|
|
81
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface TaglifyResult {
|
|
2
|
+
text: string;
|
|
3
|
+
changed: boolean;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Replaces content between HTML comment markers.
|
|
7
|
+
*
|
|
8
|
+
* Example:
|
|
9
|
+
* <!-- BADGES:START -->
|
|
10
|
+
* old content
|
|
11
|
+
* <!-- BADGES:END -->
|
|
12
|
+
*/
|
|
13
|
+
export declare const taglifyText: (text: string, tags: Record<string, string>) => TaglifyResult;
|
|
14
|
+
/**
|
|
15
|
+
* Applies tag replacements to a file.
|
|
16
|
+
*
|
|
17
|
+
* Returns true if the file was modified.
|
|
18
|
+
* Throws a friendly error if the file does not exist.
|
|
19
|
+
*/
|
|
20
|
+
export declare const taglifyFile: (filePath: string, tags: Record<string, string>) => boolean;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4
|
+
var taglifyText = (text, tags) => {
|
|
5
|
+
let output = text;
|
|
6
|
+
for (const [tagName, replacement] of Object.entries(tags)) {
|
|
7
|
+
const tag = escapeRegExp(tagName.toUpperCase());
|
|
8
|
+
const blockRegex = new RegExp(`<!-- ${tag}:START -->(.*?)<!-- ${tag}:END -->`, "gis");
|
|
9
|
+
output = output.replace(blockRegex, (_match, block) => {
|
|
10
|
+
const lineEnding = block.includes("\r\n") ? "\r\n" : "\n";
|
|
11
|
+
return `<!-- ${tag}:START -->${lineEnding}${replacement}${lineEnding}<!-- ${tag}:END -->`;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
text: output,
|
|
16
|
+
changed: output !== text
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
var taglifyFile = (filePath, tags) => {
|
|
20
|
+
let text;
|
|
21
|
+
try {
|
|
22
|
+
text = readFileSync(filePath, "utf8");
|
|
23
|
+
} catch (error) {
|
|
24
|
+
if (error.code === "ENOENT") {
|
|
25
|
+
throw new Error(`File not found: ${filePath}`);
|
|
26
|
+
}
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
const result = taglifyText(text, tags);
|
|
30
|
+
if (result.changed) {
|
|
31
|
+
writeFileSync(filePath, result.text, "utf8");
|
|
32
|
+
}
|
|
33
|
+
return result.changed;
|
|
34
|
+
};
|
|
35
|
+
export {
|
|
36
|
+
taglifyFile,
|
|
37
|
+
taglifyText
|
|
38
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "taglify",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Synchronize generated content inside marker blocks in any text file.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"markers",
|
|
7
|
+
"codegen",
|
|
8
|
+
"sync",
|
|
9
|
+
"readme",
|
|
10
|
+
"text"
|
|
11
|
+
],
|
|
12
|
+
"type": "module",
|
|
13
|
+
"private": false,
|
|
14
|
+
"sideEffects": false,
|
|
15
|
+
"main": "./dist/index.cjs",
|
|
16
|
+
"module": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js",
|
|
25
|
+
"require": "./dist/index.cjs"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@size-limit/file": "^11.0.0",
|
|
30
|
+
"@trivago/prettier-plugin-sort-imports": "^5.0.0",
|
|
31
|
+
"@types/bun": "latest",
|
|
32
|
+
"@types/node": "^22.20.1",
|
|
33
|
+
"esbuild": "^0.24.0",
|
|
34
|
+
"prettier": "^3.0.0",
|
|
35
|
+
"size-limit": "^11.0.0",
|
|
36
|
+
"typescript": "^5.6.0"
|
|
37
|
+
},
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"author": "jayF0x",
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "rm -rf dist && esbuild src/index.ts --bundle --outfile=dist/index.js --platform=node --format=esm && bun build src/index.ts --outdir dist --entry-naming index.cjs --target node --format cjs && tsc",
|
|
45
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
46
|
+
"test": "bun test",
|
|
47
|
+
"test:run": "bun test",
|
|
48
|
+
"format": "prettier --write .",
|
|
49
|
+
"format:check": "prettier --check .",
|
|
50
|
+
"npm:deploy": "bash ./scripts/publish-npm.sh",
|
|
51
|
+
"rm:stalepr": "git branch -vv | grep '\\[gone\\]' | awk '{print $1}' | xargs git branch -D",
|
|
52
|
+
"size": "size-limit",
|
|
53
|
+
"rkit:pull": "bunx repokit pull",
|
|
54
|
+
"rkit:push": "bunx repokit push"
|
|
55
|
+
},
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "git+https://github.com/jayf0x/taglify.git"
|
|
59
|
+
},
|
|
60
|
+
"homepage": "https://github.com/jayf0x/taglify#readme",
|
|
61
|
+
"bugs": {
|
|
62
|
+
"url": "https://github.com/jayf0x/taglify/issues"
|
|
63
|
+
}
|
|
64
|
+
}
|