@thi.ng/tangle 0.1.91 → 0.2.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/CHANGELOG.md +15 -1
- package/README.md +12 -6
- package/api.d.ts +19 -3
- package/api.js +14 -1
- package/package.json +15 -14
- package/tangle.js +31 -19
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2024-03-
|
|
3
|
+
- **Last updated**: 2024-03-07T20:40:47Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -9,6 +9,20 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
9
9
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
10
|
and/or version bumps of transitive dependencies.
|
|
11
11
|
|
|
12
|
+
## [0.2.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/tangle@0.2.0) (2024-03-07)
|
|
13
|
+
|
|
14
|
+
#### 🚀 Features
|
|
15
|
+
|
|
16
|
+
- add support for code blocks in JS/TS docstrings ([5b68f19](https://github.com/thi-ng/umbrella/commit/5b68f19))
|
|
17
|
+
- update CodeBlockFormat, allow regexps as prefix/suffix
|
|
18
|
+
- add optional body xform fn
|
|
19
|
+
- add ".js", ".ts" as supported file extensions
|
|
20
|
+
- update matching logic in extractBlocks()
|
|
21
|
+
|
|
22
|
+
#### 🩹 Bug fixes
|
|
23
|
+
|
|
24
|
+
- off-by-one error in extractBlocks() ([d7d7e03](https://github.com/thi-ng/umbrella/commit/d7d7e03))
|
|
25
|
+
|
|
12
26
|
### [0.1.86](https://github.com/thi-ng/umbrella/tree/@thi.ng/tangle@0.1.86) (2024-02-22)
|
|
13
27
|
|
|
14
28
|
#### ♻️ Refactoring
|
package/README.md
CHANGED
|
@@ -48,12 +48,18 @@ introduction. For all LP projects, a so-called "tangling" step is required to
|
|
|
48
48
|
produce workable, standard source code files from these documents. This package
|
|
49
49
|
provides just that:
|
|
50
50
|
|
|
51
|
-
Extract, expand, transclude, combine and assemble code blocks from
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
Extract, expand, transclude, combine and assemble code blocks from arbitrary text files into actual/traditional source code files. The following input formats are supported:
|
|
52
|
+
|
|
53
|
+
- Markdown
|
|
54
|
+
- Markdown codeblocks embedded inside docstrings of JavaScript/TypeScript source files
|
|
55
|
+
- [Org-mode](https://orgmode.org)
|
|
56
|
+
|
|
57
|
+
A single input file can contain code for multiple languages. Each individual
|
|
58
|
+
code block can define its own target file and include [noweb-style
|
|
55
59
|
references](https://orgmode.org/manual/Noweb-Reference-Syntax.html) to other
|
|
56
|
-
code blocks, either from the same or even from other files.
|
|
60
|
+
code blocks, either from the same or even from other files. If multiple code
|
|
61
|
+
blocks in the same input file reference the same output file, they will be
|
|
62
|
+
concatenated.
|
|
57
63
|
|
|
58
64
|
The package provides both a basic API and a CLI wrapper to perform the
|
|
59
65
|
"tangling" tasks (an expression borrowed from
|
|
@@ -326,7 +332,7 @@ For Node.js REPL:
|
|
|
326
332
|
const tangle = await import("@thi.ng/tangle");
|
|
327
333
|
```
|
|
328
334
|
|
|
329
|
-
Package sizes (brotli'd, pre-treeshake): ESM: 1.
|
|
335
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 1.99 KB
|
|
330
336
|
|
|
331
337
|
## Dependencies
|
|
332
338
|
|
package/api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Fn2, FnAnyT, IObjectOf, Predicate } from "@thi.ng/api";
|
|
1
|
+
import type { Fn, Fn2, FnAnyT, IObjectOf, Predicate } from "@thi.ng/api";
|
|
2
2
|
import { type ILogger } from "@thi.ng/logger";
|
|
3
3
|
export interface Block {
|
|
4
4
|
id: string;
|
|
@@ -59,8 +59,24 @@ export interface TangleOpts {
|
|
|
59
59
|
comments: boolean;
|
|
60
60
|
}
|
|
61
61
|
export interface CodeBlockFormat {
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
/**
|
|
63
|
+
* String or regexp matching the beginning of a code block. If given a
|
|
64
|
+
* regexp, it will become part of a larger one and any regexp flags given
|
|
65
|
+
* here will be ignored. Also the given regexp pattern will always be
|
|
66
|
+
* prefixed with the line-start symbol (`^`), so it must not be given
|
|
67
|
+
* here...
|
|
68
|
+
*/
|
|
69
|
+
prefix: string | RegExp;
|
|
70
|
+
/**
|
|
71
|
+
* String or regexp matching the end of a code block. If given a
|
|
72
|
+
* regexp, it MUST have the multiline flag enabled!
|
|
73
|
+
*/
|
|
74
|
+
suffix: string | RegExp;
|
|
75
|
+
/**
|
|
76
|
+
* Optional function to transform the codeblock's body (e.g. to remove any
|
|
77
|
+
* prefix characters or remove trailing whitespace).
|
|
78
|
+
*/
|
|
79
|
+
xform?: Fn<string, string>;
|
|
64
80
|
}
|
|
65
81
|
export declare const BLOCK_FORMATS: IObjectOf<CodeBlockFormat>;
|
|
66
82
|
export declare const COMMENT_FORMATS: IObjectOf<string | [string, string]>;
|
package/api.js
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { ConsoleLogger, LogLevel, ROOT } from "@thi.ng/logger";
|
|
2
|
+
import { split } from "@thi.ng/strings";
|
|
3
|
+
import { map, str, transduce } from "@thi.ng/transducers";
|
|
4
|
+
const JS_DOC = {
|
|
5
|
+
prefix: /^\s*\*\s+```/,
|
|
6
|
+
suffix: /^\s*\*\s+```/m,
|
|
7
|
+
xform: (body) => transduce(
|
|
8
|
+
map((x) => x.replace(/^\s*\*\s?/, "")),
|
|
9
|
+
str("\n"),
|
|
10
|
+
split(body)
|
|
11
|
+
)
|
|
12
|
+
};
|
|
2
13
|
const BLOCK_FORMATS = {
|
|
3
14
|
".md": {
|
|
4
15
|
prefix: "```",
|
|
@@ -7,7 +18,9 @@ const BLOCK_FORMATS = {
|
|
|
7
18
|
".org": {
|
|
8
19
|
prefix: "#+BEGIN_SRC ",
|
|
9
20
|
suffix: "#+END_SRC"
|
|
10
|
-
}
|
|
21
|
+
},
|
|
22
|
+
".js": JS_DOC,
|
|
23
|
+
".ts": JS_DOC
|
|
11
24
|
};
|
|
12
25
|
const C = "//";
|
|
13
26
|
const P = "#";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/tangle",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Literate programming code block tangling / codegen utility, inspired by org-mode & noweb",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -33,23 +33,24 @@
|
|
|
33
33
|
"doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
|
|
34
34
|
"doc:readme": "bun ../../tools/src/module-stats.ts && bun ../../tools/src/readme.ts",
|
|
35
35
|
"pub": "yarn npm publish --access public",
|
|
36
|
-
"test": "testament test"
|
|
36
|
+
"test": "testament test",
|
|
37
|
+
"tool:tangle": "../../node_modules/.bin/tangle src/**/*.ts"
|
|
37
38
|
},
|
|
38
39
|
"dependencies": {
|
|
39
|
-
"@thi.ng/api": "^8.9.
|
|
40
|
-
"@thi.ng/args": "^2.3.
|
|
41
|
-
"@thi.ng/checks": "^3.5.
|
|
42
|
-
"@thi.ng/compare": "^2.2.
|
|
43
|
-
"@thi.ng/date": "^2.7.
|
|
44
|
-
"@thi.ng/errors": "^2.4.
|
|
45
|
-
"@thi.ng/file-io": "^1.3.
|
|
46
|
-
"@thi.ng/logger": "^3.0.
|
|
47
|
-
"@thi.ng/strings": "^3.7.
|
|
48
|
-
"@thi.ng/transducers": "^8.9.
|
|
40
|
+
"@thi.ng/api": "^8.9.29",
|
|
41
|
+
"@thi.ng/args": "^2.3.22",
|
|
42
|
+
"@thi.ng/checks": "^3.5.2",
|
|
43
|
+
"@thi.ng/compare": "^2.2.25",
|
|
44
|
+
"@thi.ng/date": "^2.7.6",
|
|
45
|
+
"@thi.ng/errors": "^2.4.20",
|
|
46
|
+
"@thi.ng/file-io": "^1.3.7",
|
|
47
|
+
"@thi.ng/logger": "^3.0.5",
|
|
48
|
+
"@thi.ng/strings": "^3.7.22",
|
|
49
|
+
"@thi.ng/transducers": "^8.9.11"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"@microsoft/api-extractor": "^7.40.1",
|
|
52
|
-
"@thi.ng/testament": "^0.4.
|
|
53
|
+
"@thi.ng/testament": "^0.4.22",
|
|
53
54
|
"esbuild": "^0.20.0",
|
|
54
55
|
"rimraf": "^5.0.5",
|
|
55
56
|
"typedoc": "^0.25.7",
|
|
@@ -93,5 +94,5 @@
|
|
|
93
94
|
"status": "alpha",
|
|
94
95
|
"year": 2022
|
|
95
96
|
},
|
|
96
|
-
"gitHead": "
|
|
97
|
+
"gitHead": "69100942474942f7446ac645d59d91e7dfc352f9\n"
|
|
97
98
|
}
|
package/tangle.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { isPlainObject, isString } from "@thi.ng/checks";
|
|
2
2
|
import { compareByKey } from "@thi.ng/compare";
|
|
3
3
|
import { FMT_ISO_SHORT } from "@thi.ng/date";
|
|
4
|
-
import { defError } from "@thi.ng/errors
|
|
5
|
-
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
|
|
4
|
+
import { defError, illegalArgs, illegalState } from "@thi.ng/errors";
|
|
6
5
|
import { readText } from "@thi.ng/file-io";
|
|
7
6
|
import { split } from "@thi.ng/strings";
|
|
8
7
|
import { assocObj, map, transduce } from "@thi.ng/transducers";
|
|
@@ -19,38 +18,51 @@ const UnknownBlockError = defError(
|
|
|
19
18
|
const extractBlocks = (src, { format, logger }) => {
|
|
20
19
|
let nextID = 0;
|
|
21
20
|
const blocks = {};
|
|
22
|
-
const
|
|
23
|
-
`^${format.prefix.replace("+", "\\+")}(\\w+)\\s+(.+)$`,
|
|
21
|
+
const prefix = new RegExp(
|
|
22
|
+
(isString(format.prefix) ? `^${format.prefix.replace("+", "\\+")}` : format.prefix.source) + `(\\w+)\\s+(.+)$`,
|
|
24
23
|
"gm"
|
|
25
24
|
);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
const suffix = isString(format.suffix) ? new RegExp(`${format.suffix.replace("+", "\\+")}`) : format.suffix;
|
|
26
|
+
let matchPrefix;
|
|
27
|
+
while (matchPrefix = prefix.exec(src)) {
|
|
28
|
+
let { id, tangle, noweb, publish } = parseBlockHeader(matchPrefix[2]);
|
|
29
29
|
!id && (id = `__block-${nextID++}`);
|
|
30
|
-
const matchStart =
|
|
31
|
-
const start = src.indexOf("\n", matchStart) + 1;
|
|
32
|
-
const end = src.indexOf(`
|
|
33
|
-
${format.suffix}`, matchStart + 1);
|
|
30
|
+
const matchStart = matchPrefix.index;
|
|
31
|
+
const start = src.indexOf("\n", matchStart + 1) + 1;
|
|
34
32
|
logger.debug(
|
|
35
|
-
"codeblock",
|
|
33
|
+
"codeblock ID:",
|
|
36
34
|
id,
|
|
37
|
-
|
|
38
|
-
end,
|
|
35
|
+
"matchStart:",
|
|
39
36
|
matchStart,
|
|
40
|
-
|
|
37
|
+
"start:",
|
|
38
|
+
start
|
|
39
|
+
);
|
|
40
|
+
const matchSuffix = suffix.exec(src.substring(start));
|
|
41
|
+
if (!matchSuffix)
|
|
42
|
+
illegalState("no codeblock end found");
|
|
43
|
+
const end = start + matchSuffix.index;
|
|
44
|
+
const matchEnd = end + matchSuffix[0].length + 1;
|
|
45
|
+
logger.debug(
|
|
46
|
+
"codeblock ID:",
|
|
47
|
+
id,
|
|
48
|
+
"end:",
|
|
49
|
+
end,
|
|
50
|
+
"matchEnd:",
|
|
51
|
+
matchEnd,
|
|
52
|
+
matchSuffix[0]
|
|
41
53
|
);
|
|
42
|
-
const body = src.substring(start, end);
|
|
54
|
+
const body = src.substring(start, end - 1);
|
|
43
55
|
blocks[id] = {
|
|
44
56
|
id,
|
|
45
|
-
lang:
|
|
57
|
+
lang: matchPrefix[1],
|
|
46
58
|
tangle,
|
|
47
59
|
publish,
|
|
48
60
|
noweb,
|
|
49
61
|
start,
|
|
50
62
|
end,
|
|
51
63
|
matchStart,
|
|
52
|
-
matchEnd
|
|
53
|
-
body
|
|
64
|
+
matchEnd,
|
|
65
|
+
body: format.xform ? format.xform(body) : body
|
|
54
66
|
};
|
|
55
67
|
}
|
|
56
68
|
return blocks;
|