summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Drew Powers <drew@pow.rs> 2021-03-18 18:10:08 -0600
committerGravatar Drew Powers <drew@pow.rs> 2021-03-18 18:10:08 -0600
commitd75107a20e971ad26a0398229b2b3fd13c45c6ee (patch)
tree850ae9112a20916501e98324b57510ed8785c315 /src
parentd27bd74b055b23a6eb455969755b3ee7f687fd61 (diff)
downloadastro-d75107a20e971ad26a0398229b2b3fd13c45c6ee.tar.gz
astro-d75107a20e971ad26a0398229b2b3fd13c45c6ee.tar.zst
astro-d75107a20e971ad26a0398229b2b3fd13c45c6ee.zip
Respect comments when scanning imports
Use es-module-lexer for import scanning in HMX scripts
Diffstat (limited to 'src')
-rw-r--r--src/@types/astro.ts9
-rw-r--r--src/@types/compiler.ts2
-rw-r--r--src/codegen/index.ts21
-rw-r--r--src/dev.ts4
-rw-r--r--src/optimize/index.ts34
-rw-r--r--src/optimize/styles.ts30
-rw-r--r--src/style.ts2
-rw-r--r--src/transform2.ts20
8 files changed, 66 insertions, 56 deletions
diff --git a/src/@types/astro.ts b/src/@types/astro.ts
index 02dcc8cf3..f7170cb61 100644
--- a/src/@types/astro.ts
+++ b/src/@types/astro.ts
@@ -14,3 +14,12 @@ export interface JsxItem {
name: string;
jsx: string;
}
+
+export interface TransformResult {
+ script: string;
+ items: JsxItem[];
+}
+
+export interface CompileResult {
+ contents: string;
+}
diff --git a/src/@types/compiler.ts b/src/@types/compiler.ts
index 343aa548b..456924267 100644
--- a/src/@types/compiler.ts
+++ b/src/@types/compiler.ts
@@ -3,4 +3,4 @@ import type { LogOptions } from '../logger';
export interface CompileOptions {
logging: LogOptions;
resolve: (p: string) => string;
-} \ No newline at end of file
+}
diff --git a/src/codegen/index.ts b/src/codegen/index.ts
index c0f4199c6..3257d9936 100644
--- a/src/codegen/index.ts
+++ b/src/codegen/index.ts
@@ -1,6 +1,6 @@
import type { CompileOptions } from '../@types/compiler';
import type { Ast, TemplateNode } from '../compiler/interfaces';
-import type { JsxItem } from '../@types/astro.js';
+import type { JsxItem, TransformResult } from '../@types/astro.js';
import eslexer from 'es-module-lexer';
import esbuild from 'esbuild';
@@ -14,13 +14,13 @@ interface Attribute {
end: number;
type: 'Attribute';
name: string;
- value: any
+ value: any;
}
interface CodeGenOptions {
compileOptions: CompileOptions;
filename: string;
- fileID: string
+ fileID: string;
}
function internalImport(internalPath: string) {
@@ -144,14 +144,12 @@ function getComponentWrapper(_name: string, { type, url }: { type: string; url:
throw new Error('Unknown Component Type: ' + name);
}
-const patternImport = new RegExp(/import(?:["'\s]*([\w*${}\n\r\t, ]+)from\s*)?["'\s]["'\s](.*[@\w_-]+)["'\s].*;$/, 'mg');
function compileScriptSafe(raw: string, loader: 'jsx' | 'tsx'): string {
// esbuild treeshakes unused imports. In our case these are components, so let's keep them.
- const imports: Array<string> = [];
- raw.replace(patternImport, (value: string) => {
- imports.push(value);
- return value;
- });
+ const imports = eslexer
+ .parse(raw)[0]
+ .filter(({ d }) => d === -1)
+ .map((i: any) => raw.substring(i.ss, i.se));
let { code } = transformSync(raw, {
loader,
@@ -169,7 +167,8 @@ function compileScriptSafe(raw: string, loader: 'jsx' | 'tsx'): string {
return code;
}
-export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions) {
+export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Promise<TransformResult> {
+ await eslexer.init;
const script = compileScriptSafe(ast.instance ? ast.instance.content : '', 'tsx');
// Compile scripts as TypeScript, always
@@ -339,4 +338,4 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions) {
script: script + '\n' + Array.from(additionalImports).join('\n'),
items,
};
-} \ No newline at end of file
+}
diff --git a/src/dev.ts b/src/dev.ts
index d2a268ef6..524379dd1 100644
--- a/src/dev.ts
+++ b/src/dev.ts
@@ -16,7 +16,7 @@ snowpackLogger.level = 'silent';
const logging: LogOptions = {
level: 'debug',
- dest: defaultLogDestination
+ dest: defaultLogDestination,
};
export default async function (astroConfig: AstroConfig) {
@@ -97,7 +97,7 @@ export default async function (astroConfig: AstroConfig) {
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end(html);
} catch (err) {
- switch(err.code) {
+ switch (err.code) {
case 'parse-error': {
err.filename = pathRelative(projectRoot.pathname, err.filename);
debugger;
diff --git a/src/optimize/index.ts b/src/optimize/index.ts
index d22854a32..a0604b1c8 100644
--- a/src/optimize/index.ts
+++ b/src/optimize/index.ts
@@ -10,8 +10,8 @@ interface VisitorCollection {
}
function addVisitor(visitor: NodeVisitor, collection: VisitorCollection, nodeName: string, event: 'enter' | 'leave') {
- if(event in visitor) {
- if(collection[event].has(nodeName)) {
+ if (event in visitor) {
+ if (collection[event].has(nodeName)) {
collection[event].get(nodeName)!.push(visitor[event]!);
}
@@ -20,15 +20,15 @@ function addVisitor(visitor: NodeVisitor, collection: VisitorCollection, nodeNam
}
function collectVisitors(optimizer: Optimizer, htmlVisitors: VisitorCollection, cssVisitors: VisitorCollection, finalizers: Array<() => Promise<void>>) {
- if(optimizer.visitors) {
- if(optimizer.visitors.html) {
- for(const [nodeName, visitor] of Object.entries(optimizer.visitors.html)) {
+ if (optimizer.visitors) {
+ if (optimizer.visitors.html) {
+ for (const [nodeName, visitor] of Object.entries(optimizer.visitors.html)) {
addVisitor(visitor, htmlVisitors, nodeName, 'enter');
addVisitor(visitor, htmlVisitors, nodeName, 'leave');
}
}
- if(optimizer.visitors.css) {
- for(const [nodeName, visitor] of Object.entries(optimizer.visitors.css)) {
+ if (optimizer.visitors.css) {
+ for (const [nodeName, visitor] of Object.entries(optimizer.visitors.css)) {
addVisitor(visitor, cssVisitors, nodeName, 'enter');
addVisitor(visitor, cssVisitors, nodeName, 'leave');
}
@@ -47,27 +47,27 @@ function createVisitorCollection() {
function walkAstWithVisitors(tmpl: TemplateNode, collection: VisitorCollection) {
walk(tmpl, {
enter(node) {
- if(collection.enter.has(node.type)) {
+ if (collection.enter.has(node.type)) {
const fns = collection.enter.get(node.type)!;
- for(let fn of fns) {
+ for (let fn of fns) {
fn(node);
}
}
},
leave(node) {
- if(collection.leave.has(node.type)) {
+ if (collection.leave.has(node.type)) {
const fns = collection.leave.get(node.type)!;
- for(let fn of fns) {
+ for (let fn of fns) {
fn(node);
}
}
- }
+ },
});
}
-interface OptimizeOptions {
- filename: string,
- fileID: string
+interface OptimizeOptions {
+ filename: string;
+ fileID: string;
}
export async function optimize(ast: Ast, opts: OptimizeOptions) {
@@ -81,5 +81,5 @@ export async function optimize(ast: Ast, opts: OptimizeOptions) {
walkAstWithVisitors(ast.css, cssVisitors);
// Run all of the finalizer functions in parallel because why not.
- await Promise.all(finalizers.map(fn => fn()));
-} \ No newline at end of file
+ await Promise.all(finalizers.map((fn) => fn()));
+}
diff --git a/src/optimize/styles.ts b/src/optimize/styles.ts
index b654ca7d1..6d15cb602 100644
--- a/src/optimize/styles.ts
+++ b/src/optimize/styles.ts
@@ -1,8 +1,8 @@
import type { Ast, TemplateNode } from '../compiler/interfaces';
-import type { Optimizer } from './types'
+import type { Optimizer } from './types';
import { transformStyle } from '../style.js';
-export default function({ filename, fileID }: { filename: string, fileID: string }): Optimizer {
+export default function ({ filename, fileID }: { filename: string; fileID: string }): Optimizer {
const classNames: Set<string> = new Set();
let stylesPromises: any[] = [];
@@ -11,20 +11,20 @@ export default function({ filename, fileID }: { filename: string, fileID: string
html: {
Element: {
enter(node) {
- for(let attr of node.attributes) {
- if(attr.name === 'class') {
- for(let value of attr.value) {
- if(value.type === 'Text') {
+ for (let attr of node.attributes) {
+ if (attr.name === 'class') {
+ for (let value of attr.value) {
+ if (value.type === 'Text') {
const classes = value.data.split(' ');
- for(const className in classes) {
+ for (const className in classes) {
classNames.add(className);
}
}
}
}
}
- }
- }
+ },
+ },
},
css: {
Style: {
@@ -39,13 +39,13 @@ export default function({ filename, fileID }: { filename: string, fileID: string
fileID,
})
); // TODO: styles needs to go in <head>
- }
- }
- }
+ },
+ },
+ },
},
async finalize() {
const styles = await Promise.all(stylesPromises); // TODO: clean this up
- console.log({ styles });
- }
+ // console.log({ styles });
+ },
};
-} \ No newline at end of file
+}
diff --git a/src/style.ts b/src/style.ts
index 527c13f99..489f22ce8 100644
--- a/src/style.ts
+++ b/src/style.ts
@@ -85,7 +85,7 @@ export async function transformStyle(
}),
autoprefixer(),
])
- .process(css, { from: filename })
+ .process(css, { from: filename, to: undefined })
.then((result) => result.css);
return { css, cssModules };
diff --git a/src/transform2.ts b/src/transform2.ts
index 84277efdf..047ccc3d0 100644
--- a/src/transform2.ts
+++ b/src/transform2.ts
@@ -1,12 +1,11 @@
import type { LogOptions } from './logger.js';
import path from 'path';
-import esbuild from 'esbuild';
-import eslexer from 'es-module-lexer';
import micromark from 'micromark';
import gfmSyntax from 'micromark-extension-gfm';
import matter from 'gray-matter';
import gfmHtml from 'micromark-extension-gfm/html.js';
+import { CompileResult, TransformResult } from './@types/astro';
import { parse } from './compiler/index.js';
import markdownEncode from './markdown-encode.js';
import { defaultLogOptions } from './logger.js';
@@ -30,12 +29,11 @@ function internalImport(internalPath: string) {
interface ConvertHmxOptions {
compileOptions: CompileOptions;
filename: string;
- fileID: string
+ fileID: string;
}
-async function convertHmxToJsx(template: string, opts: ConvertHmxOptions) {
+async function convertHmxToJsx(template: string, opts: ConvertHmxOptions): Promise<TransformResult> {
const { filename } = opts;
- await eslexer.init;
// 1. Parse
const ast = parse(template, {
@@ -49,7 +47,10 @@ async function convertHmxToJsx(template: string, opts: ConvertHmxOptions) {
return await codegen(ast, opts);
}
-async function convertMdToJsx(contents: string, { compileOptions, filename, fileID }: { compileOptions: CompileOptions; filename: string; fileID: string }) {
+async function convertMdToJsx(
+ contents: string,
+ { compileOptions, filename, fileID }: { compileOptions: CompileOptions; filename: string; fileID: string }
+): Promise<TransformResult> {
// This doesn't work.
const { data: _frontmatterData, content } = matter(contents);
const mdHtml = micromark(content, {
@@ -84,7 +85,7 @@ async function convertMdToJsx(contents: string, { compileOptions, filename, file
async function transformFromSource(
contents: string,
{ compileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string }
-): Promise<ReturnType<typeof convertHmxToJsx>> {
+): Promise<TransformResult> {
const fileID = path.relative(projectRoot, filename);
switch (path.extname(filename)) {
case '.hmx':
@@ -99,8 +100,9 @@ async function transformFromSource(
export async function compilePage(
source: string,
{ compileOptions = defaultCompileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string }
-) {
+): Promise<CompileResult> {
const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot });
+
const headItem = sourceJsx.items.find((item) => item.name === 'head');
const bodyItem = sourceJsx.items.find((item) => item.name === 'body');
const headItemJsx = !headItem ? 'null' : headItem.jsx.replace('"head"', 'isRoot ? "head" : Fragment');
@@ -122,7 +124,7 @@ export function body({title, description, props}, child, isRoot) { return (${bod
export async function compileComponent(
source: string,
{ compileOptions = defaultCompileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string }
-) {
+): Promise<CompileResult> {
const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot });
const componentJsx = sourceJsx.items.find((item) => item.name === 'Component');
if (!componentJsx) {