@markii/core 0.13.0 → 0.14.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/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/parse.d.ts +19 -0
- package/dist/parse.js +19 -1
- package/dist/scripts.d.ts +18 -0
- package/dist/scripts.js +22 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { parse } from './parse.js';
|
|
1
|
+
export { parse, isRecognizedTextDirective } from './parse.js';
|
|
2
2
|
export { extractFrontmatter, extractFrontmatterUses, type Frontmatter, } from './frontmatter.js';
|
|
3
3
|
export { toHast, nodeToHast, isSafeUrl, type MarkNode } from './to-hast.js';
|
|
4
4
|
export { extractScripts, isBareAttribute, isValidScriptName, parseMetaAttributes, type ScriptBlock, } from './scripts.js';
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// subpath instead of here so a browser bundler consuming `@markii/core` (e.g.
|
|
5
5
|
// via `@markii/react`) never has to reason about Node built-ins reachable from
|
|
6
6
|
// its entry point.
|
|
7
|
-
export { parse } from './parse.js';
|
|
7
|
+
export { parse, isRecognizedTextDirective } from './parse.js';
|
|
8
8
|
export { extractFrontmatter, extractFrontmatterUses, } from './frontmatter.js';
|
|
9
9
|
export { toHast, nodeToHast, isSafeUrl } from './to-hast.js';
|
|
10
10
|
export { extractScripts, isBareAttribute, isValidScriptName, parseMetaAttributes, } from './scripts.js';
|
package/dist/parse.d.ts
CHANGED
|
@@ -27,3 +27,22 @@ import type { Root } from 'mdast';
|
|
|
27
27
|
* format-defined key (`uses`) off that raw text for the simple list forms.
|
|
28
28
|
*/
|
|
29
29
|
export declare function parse(text: string): Root;
|
|
30
|
+
/**
|
|
31
|
+
* The word-start DEMOTION rule (GitHub issue #43): whether an already
|
|
32
|
+
* tokenized text directive (`remark-directive` has already decided a run
|
|
33
|
+
* of text looks like `:name[...]`) should be KEPT as a directive or
|
|
34
|
+
* demoted back to plain text, per `demoteInvalidTextDirectives` above.
|
|
35
|
+
*
|
|
36
|
+
* This is scoped narrowly on purpose: it is not the rule that decides
|
|
37
|
+
* where a directive starts. That decision, and the colon-run and bracket
|
|
38
|
+
* grammar (how many colons open which directive form, what counts as a
|
|
39
|
+
* closing bracket), live entirely in `remark-directive` upstream and are
|
|
40
|
+
* not exposed here. This function only answers the one question this
|
|
41
|
+
* module adds on top: given a text directive `remark-directive` already
|
|
42
|
+
* found, does its name start with a letter, and does its colon sit at a
|
|
43
|
+
* word start? A third-party tokenizer (a Lezer grammar, for instance) that
|
|
44
|
+
* adopts this predicate gets parity on that one word-start rule and
|
|
45
|
+
* nothing more — it still needs its own colon-run and bracket handling to
|
|
46
|
+
* match `remark-directive`'s grammar.
|
|
47
|
+
*/
|
|
48
|
+
export declare function isRecognizedTextDirective(name: string, colonOffset: number, source: string): boolean;
|
package/dist/parse.js
CHANGED
|
@@ -94,7 +94,25 @@ function demoteInvalidTextDirectives(tree, source) {
|
|
|
94
94
|
const STARTS_WITH_LETTER = /^[A-Za-z]/;
|
|
95
95
|
/** ASCII letter-or-digit check for the character immediately before the colon. */
|
|
96
96
|
const IS_WORD_CHARACTER = /[A-Za-z0-9]/;
|
|
97
|
-
|
|
97
|
+
/**
|
|
98
|
+
* The word-start DEMOTION rule (GitHub issue #43): whether an already
|
|
99
|
+
* tokenized text directive (`remark-directive` has already decided a run
|
|
100
|
+
* of text looks like `:name[...]`) should be KEPT as a directive or
|
|
101
|
+
* demoted back to plain text, per `demoteInvalidTextDirectives` above.
|
|
102
|
+
*
|
|
103
|
+
* This is scoped narrowly on purpose: it is not the rule that decides
|
|
104
|
+
* where a directive starts. That decision, and the colon-run and bracket
|
|
105
|
+
* grammar (how many colons open which directive form, what counts as a
|
|
106
|
+
* closing bracket), live entirely in `remark-directive` upstream and are
|
|
107
|
+
* not exposed here. This function only answers the one question this
|
|
108
|
+
* module adds on top: given a text directive `remark-directive` already
|
|
109
|
+
* found, does its name start with a letter, and does its colon sit at a
|
|
110
|
+
* word start? A third-party tokenizer (a Lezer grammar, for instance) that
|
|
111
|
+
* adopts this predicate gets parity on that one word-start rule and
|
|
112
|
+
* nothing more — it still needs its own colon-run and bracket handling to
|
|
113
|
+
* match `remark-directive`'s grammar.
|
|
114
|
+
*/
|
|
115
|
+
export function isRecognizedTextDirective(name, colonOffset, source) {
|
|
98
116
|
if (!STARTS_WITH_LETTER.test(name))
|
|
99
117
|
return false;
|
|
100
118
|
if (colonOffset === 0)
|
package/dist/scripts.d.ts
CHANGED
|
@@ -16,6 +16,22 @@ import type { Code, Root } from 'mdast';
|
|
|
16
16
|
* ` ```lua {src=scripts/etl.lua name=stars}` ` with an empty body"); `code`
|
|
17
17
|
* is still the fence's own body (empty for a `src=` reference).
|
|
18
18
|
*
|
|
19
|
+
* `permissions`, when present, is the script fence's own declared list of
|
|
20
|
+
* hostnames (` ```lua {name=gh permissions=api.github.com}` `, or
|
|
21
|
+
* comma-separated for more than one:
|
|
22
|
+
* `permissions=api.github.com,api.weather.com`). It is DISPLAY-ONLY: a
|
|
23
|
+
* grant prompt may show it next to the hosts a static scan actually finds
|
|
24
|
+
* ("declares: ..."), and a mismatch between the two is a diagnostics line,
|
|
25
|
+
* mirroring how a bundle manifest's `permissions.net` is already
|
|
26
|
+
* display-only against the same scan
|
|
27
|
+
* (`@markii/host`'s `script-requirements.ts`). It is NEVER an input to
|
|
28
|
+
* what gets granted — the literal-URL closure scan stays the only source
|
|
29
|
+
* of truth for that. Absent for a script with no `permissions` attribute
|
|
30
|
+
* at all; an empty comma-separated list (`permissions=`, or a value with
|
|
31
|
+
* no non-empty segment) is treated the same as absent, not as "declares
|
|
32
|
+
* nothing", since the format's script names are lowercase-hostname-shaped
|
|
33
|
+
* text with no way to write an empty entry on purpose.
|
|
34
|
+
*
|
|
19
35
|
* `publish`, when present, is always `true` — docs/scripting.md: "**Publishing is
|
|
20
36
|
* declarative**: the bare `publish` attribute on the script fence, no API to
|
|
21
37
|
* call." "Bare" is load-bearing: it is set ONLY when the fence spells the
|
|
@@ -44,6 +60,8 @@ export interface ScriptBlock {
|
|
|
44
60
|
src?: string;
|
|
45
61
|
code: string;
|
|
46
62
|
publish?: true;
|
|
63
|
+
/** See `permissions`'s doc comment above. Omitted, never an empty array, when the fence declares none. */
|
|
64
|
+
permissions?: string[];
|
|
47
65
|
position?: Code['position'];
|
|
48
66
|
}
|
|
49
67
|
/**
|
package/dist/scripts.js
CHANGED
|
@@ -134,6 +134,25 @@ export function isBareAttribute(meta, key) {
|
|
|
134
134
|
}
|
|
135
135
|
return bare;
|
|
136
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Splits a script fence's `permissions` attribute value into a list of
|
|
139
|
+
* declared hostnames: comma-separated, each segment trimmed and
|
|
140
|
+
* lowercased (matching `@markii/host`'s `manifestNetHosts` case-folding
|
|
141
|
+
* for the bundle-manifest equivalent, so the two declared-vs-scanned
|
|
142
|
+
* comparisons stay on the same footing), empty segments dropped. Returns
|
|
143
|
+
* `undefined` for a missing/empty attribute or one with no non-empty
|
|
144
|
+
* segment, per `ScriptBlock.permissions`'s doc comment — never an empty
|
|
145
|
+
* array.
|
|
146
|
+
*/
|
|
147
|
+
function parsePermissions(raw) {
|
|
148
|
+
if (!raw)
|
|
149
|
+
return undefined;
|
|
150
|
+
const hosts = raw
|
|
151
|
+
.split(',')
|
|
152
|
+
.map((host) => host.trim().toLowerCase())
|
|
153
|
+
.filter((host) => host.length > 0);
|
|
154
|
+
return hosts.length > 0 ? hosts : undefined;
|
|
155
|
+
}
|
|
137
156
|
/**
|
|
138
157
|
* Walks a parsed mdast `Root` and returns every script block, in document
|
|
139
158
|
* order. A `code` node is a script iff its `meta` carries a `{...}`
|
|
@@ -158,6 +177,9 @@ export function extractScripts(tree) {
|
|
|
158
177
|
};
|
|
159
178
|
if (attrs.src)
|
|
160
179
|
block.src = attrs.src;
|
|
180
|
+
const permissions = parsePermissions(attrs.permissions);
|
|
181
|
+
if (permissions)
|
|
182
|
+
block.permissions = permissions;
|
|
161
183
|
// Bare-only, per `ScriptBlock.publish`'s doc comment and
|
|
162
184
|
// `isBareAttribute`'s: a plain `attrs.publish === ''` check can't tell
|
|
163
185
|
// `{publish}` from `{publish=""}` (both flatten to `''`), so this asks
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markii/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Framework-agnostic reference parser for Mark (.mk.md): CommonMark + directives to mdast, and mdast to a sanitized hast tree. Zero React dependency.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|