summaryrefslogtreecommitdiff
path: root/packages/astro-parser
diff options
context:
space:
mode:
Diffstat (limited to 'packages/astro-parser')
-rw-r--r--packages/astro-parser/src/interfaces.ts16
-rw-r--r--packages/astro-parser/src/parse/state/codefence.ts38
-rw-r--r--packages/astro-parser/src/parse/state/codespan.ts25
-rw-r--r--packages/astro-parser/src/parse/state/fragment.ts11
-rw-r--r--packages/astro-parser/src/parse/state/tag.ts3
-rw-r--r--packages/astro-parser/src/parse/state/text.ts2
6 files changed, 91 insertions, 4 deletions
diff --git a/packages/astro-parser/src/interfaces.ts b/packages/astro-parser/src/interfaces.ts
index efe971941..40eeb04f5 100644
--- a/packages/astro-parser/src/interfaces.ts
+++ b/packages/astro-parser/src/interfaces.ts
@@ -20,6 +20,20 @@ export interface Text extends BaseNode {
raw: string;
}
+export interface CodeFence extends BaseNode {
+ type: 'CodeFence';
+ metadata: string;
+ data: string;
+ raw: string;
+}
+
+export interface CodeSpan extends BaseNode {
+ type: 'CodeFence';
+ metadata: string;
+ data: string;
+ raw: string;
+}
+
export interface Attribute extends BaseNode {
type: 'Attribute';
name: string;
@@ -48,7 +62,7 @@ export interface Transition extends BaseDirective {
export type Directive = BaseDirective | Transition;
-export type TemplateNode = Text | MustacheTag | BaseNode | Directive | Transition;
+export type TemplateNode = Text | CodeSpan | CodeFence | MustacheTag | BaseNode | Directive | Transition;
export interface Expression {
type: 'Expression';
diff --git a/packages/astro-parser/src/parse/state/codefence.ts b/packages/astro-parser/src/parse/state/codefence.ts
new file mode 100644
index 000000000..d5b498a0f
--- /dev/null
+++ b/packages/astro-parser/src/parse/state/codefence.ts
@@ -0,0 +1,38 @@
+// @ts-nocheck
+import { Parser } from '../index.js';
+
+export default function codefence(parser: Parser) {
+ const start = parser.index;
+ const open = parser.match_regex(/[`~]{3,}/);
+ parser.index += open!.length;
+
+ let raw = open + '';
+
+ while (parser.index < parser.template.length && !parser.match(open)) {
+ raw += parser.template[parser.index++];
+ }
+
+ parser.eat(open, true);
+ raw += open;
+ const trailingWhitespace = parser.read_until(/\S/);
+ const { metadata, data } = extractCodeFence(raw);
+
+ const node = {
+ start,
+ end: parser.index,
+ type: 'CodeFence',
+ raw: `${raw}` + trailingWhitespace,
+ metadata,
+ data
+ };
+
+ parser.current().children.push(node);
+}
+
+/** Extract attributes on first line */
+function extractCodeFence(str: string) {
+ const [_, leadingLine] = str.match(/(^[^\n]*\r?\n)/m) ?? ['', ''];
+ const metadata = leadingLine.trim();
+ const data = str.slice(leadingLine.length);
+ return { metadata, data };
+}
diff --git a/packages/astro-parser/src/parse/state/codespan.ts b/packages/astro-parser/src/parse/state/codespan.ts
new file mode 100644
index 000000000..b685800a7
--- /dev/null
+++ b/packages/astro-parser/src/parse/state/codespan.ts
@@ -0,0 +1,25 @@
+// @ts-nocheck
+import { Parser } from '../index.js';
+
+export default function codespan(parser: Parser) {
+ const start = parser.index;
+ const open = parser.match_regex(/(?<!\\)`{1,2}/);
+ parser.index += open!.length;
+
+ let raw = open;
+ while (parser.index < parser.template.length && !parser.match(open)) {
+ raw += parser.template[parser.index++];
+ }
+ parser.eat(open, true);
+ raw += open;
+
+ const node = {
+ start,
+ end: parser.index,
+ type: 'CodeSpan',
+ raw,
+ data: raw?.slice(open?.length, open?.length * -1).replace(/^ /, '').replace(/ $/, '')
+ };
+
+ parser.current().children.push(node);
+}
diff --git a/packages/astro-parser/src/parse/state/fragment.ts b/packages/astro-parser/src/parse/state/fragment.ts
index 97398b227..d3b30f329 100644
--- a/packages/astro-parser/src/parse/state/fragment.ts
+++ b/packages/astro-parser/src/parse/state/fragment.ts
@@ -2,6 +2,8 @@ import tag from './tag.js';
import setup from './setup.js';
import mustache from './mustache.js';
import text from './text.js';
+import codefence from './codefence.js';
+import codespan from './codespan.js';
import { Parser } from '../index.js';
export default function fragment(parser: Parser) {
@@ -9,6 +11,15 @@ export default function fragment(parser: Parser) {
return setup;
}
+ // Fenced code blocks are pretty complex in the GFM spec
+ // https://github.github.com/gfm/#fenced-code-blocks
+ if (parser.match_regex(/[`~]{3,}/)) {
+ return codefence;
+ }
+ if (parser.match_regex(/(?<!\\)`{1,2}/)) {
+ return codespan;
+ }
+
if (parser.match('<')) {
return tag;
}
diff --git a/packages/astro-parser/src/parse/state/tag.ts b/packages/astro-parser/src/parse/state/tag.ts
index 65bb93b4b..b8c3e63ad 100644
--- a/packages/astro-parser/src/parse/state/tag.ts
+++ b/packages/astro-parser/src/parse/state/tag.ts
@@ -1,7 +1,6 @@
// @ts-nocheck
import read_expression from '../read/expression.js';
-import read_script from '../read/script.js';
import read_style from '../read/style.js';
import { decode_character_references, closing_tag_omitted } from '../utils/html.js';
import { is_void } from '../../utils/names.js';
@@ -518,7 +517,7 @@ function read_attribute_value(parser: Parser) {
return value;
}
-function read_sequence(parser: Parser, done: () => boolean): TemplateNode[] {
+export function read_sequence(parser: Parser, done: () => boolean): TemplateNode[] {
let current_chunk: Text = {
start: parser.index,
end: null,
diff --git a/packages/astro-parser/src/parse/state/text.ts b/packages/astro-parser/src/parse/state/text.ts
index cca83f2d4..eac810a0a 100644
--- a/packages/astro-parser/src/parse/state/text.ts
+++ b/packages/astro-parser/src/parse/state/text.ts
@@ -8,7 +8,7 @@ export default function text(parser: Parser) {
let data = '';
- while (parser.index < parser.template.length && !parser.match('---') && !parser.match('<') && !parser.match('{')) {
+ while (parser.index < parser.template.length && !parser.match('---') && !parser.match('<') && !parser.match('{') && !parser.match('`')) {
data += parser.template[parser.index++];
}