refactor: extend babels file API and use their hub (#1578)

This commit is contained in:
Dylan Piercey 2020-07-07 11:11:13 -07:00 committed by GitHub
parent 14a769d201
commit 0545aa8d29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 544 additions and 479 deletions

View File

@ -30,7 +30,9 @@ export function isMacroTag(path) {
}
export function getMacroIdentifier(path) {
return !isDynamicTag(path) && path.hub.macros[path.get("name.value").node];
return (
!isDynamicTag(path) && path.hub.file._macros[path.get("name.value").node]
);
}
export function getTagDef(path) {
@ -40,8 +42,10 @@ export function getTagDef(path) {
return cached.node;
}
const { hub } = path;
const { lookup } = hub;
const {
hub: { file }
} = path;
const { _lookup } = file;
let tagName;
if (!(isMacroTag(path) || isDynamicTag(path))) {
@ -50,7 +54,7 @@ export function getTagDef(path) {
: path.get("name.value").node;
}
const tagDef = (tagName && lookup.getTag(tagName)) || null;
const tagDef = (tagName && _lookup.getTag(tagName)) || null;
path.set("tagDef", tagDef);
return tagDef;
}

View File

@ -0,0 +1,205 @@
import path from "path";
import { types as t } from "@marko/babel-types";
import { File } from "@babel/core";
import { parse, parseExpression } from "@babel/parser";
import { codeFrameColumns } from "@babel/code-frame";
import { getClientPath } from "lasso-modules-client/transport";
import { buildLookup } from "../taglib";
import { getLoc, getLocRange } from "./util/get-loc";
import checksum from "./util/checksum";
const CWD = process.cwd();
export class MarkoFile extends File {
constructor(filename, code, jsParseOptions, markoOptions) {
const start = { line: 0, column: 0 };
const end = getLoc(code, code.length);
const loc = { start, end, loc: { start, end } };
super(
{
filename,
code
},
{
code,
ast: {
type: "File",
...loc,
program: {
type: "Program",
sourceType: "module",
...loc,
body: [],
directives: []
}
}
}
);
this._jsParseOptions = jsParseOptions;
this._markoOptions = markoOptions;
this._lookup = buildLookup(path.dirname(filename), markoOptions.translator);
this._imports = Object.create(null);
this._macros = Object.create(null);
this._meta = {
id: checksum(this.getClientPath(filename)),
deps: [],
tags: []
};
}
addHelper() {
throw new Error("addHelper is not supported during a Marko transform");
}
buildCodeFrameError(node, msg, Error = SyntaxError) {
const start = getLoc(this.code, node.start);
const end = node.end != null && getLoc(this.code, node.end);
const frame = codeFrameColumns(
this.code,
{ start, end },
{ highlightCode: true }
);
const position = start.column
? `(${start.line},${start.column})`
: `:${start.line || 0}`;
return new Error(
`${path.relative(CWD, this.opts.filename)}${position}: ${msg}\n${frame}`
);
}
// TODO: all methods not implemented by `@babel/core File` should be moved into helpers in `@marko/babel-utils`.
getWhitespaceBefore(pos) {
return (
this._codeAsWhitespace ||
(this._codeAsWhitespace = this.code.replace(/[^\n\r ]/g, " "))
).slice(0, pos);
}
getClientPath(filename) {
return getClientPath(filename);
}
resolveRelativePath(filename) {
const dir = path.dirname(this.opts.filename);
let relativePath = path.isAbsolute(filename)
? path.relative(dir, filename)
: filename;
if (/^[^./]/.test(relativePath)) relativePath = `./${relativePath}`;
return relativePath.replace(/^(?:\.{1,2}\/)+node_modules\//, "");
}
importDefault(path, filename, nameHint) {
filename = remapProductionMarkoBuild(path, filename);
const { _imports } = this;
let importDeclaration = _imports[filename];
if (!importDeclaration) {
importDeclaration = _imports[filename] = this.path.pushContainer(
"body",
t.importDeclaration([], t.stringLiteral(filename))
)[0];
}
if (!nameHint) {
return;
}
const specifiers = importDeclaration.get("specifiers");
const specifier = specifiers.find(specifier =>
specifier.isImportDefaultSpecifier()
);
if (!specifier) {
const identifier = path.scope.generateUidIdentifier(nameHint);
importDeclaration.pushContainer(
"specifiers",
t.importDefaultSpecifier(identifier)
);
return identifier;
}
return t.identifier(specifier.node.local.name);
}
importNamed(path, filename, name, nameHint = name) {
filename = remapProductionMarkoBuild(path, filename);
const { _imports } = this;
let importDeclaration = _imports[filename];
if (!importDeclaration) {
importDeclaration = _imports[filename] = this.path.pushContainer(
"body",
t.importDeclaration([], t.stringLiteral(filename))
)[0];
}
const specifiers = importDeclaration.get("specifiers");
const specifier = specifiers.find(
specifier =>
specifier.isImportSpecifier() && specifier.node.imported.name === name
);
if (!specifier) {
const identifier = path.scope.generateUidIdentifier(nameHint);
importDeclaration.pushContainer(
"specifiers",
t.importSpecifier(identifier, t.identifier(name))
);
return identifier;
}
return t.identifier(specifier.node.local.name);
}
addStaticNode(node) {
this.path.pushContainer("body", node);
}
createNode(type, start, end, ...args) {
return {
...t[type](...args),
...getLocRange(this.code, start, end)
};
}
parse(str, start) {
return this._tryParseJS(false, str, start);
}
parseExpression(str, start) {
return this._tryParseJS(true, str, start);
}
_tryParseJS(isExpression, str, start) {
const opts = this._jsParseOptions;
str = this.getWhitespaceBefore(start) + str;
try {
return isExpression
? parseExpression(str, opts)
: parse(str, opts).program;
} catch (err) {
let { pos, message } = err;
if (pos) {
throw this.buildCodeFrameError(
{ start: pos },
message.replace(/ *\(\d+:\d+\)$/, "")
);
} else {
throw err;
}
}
}
}
function remapProductionMarkoBuild(path, filename) {
const {
hub: {
file: {
_markoOptions: { isProduction }
}
}
} = path;
if (!isProduction) return filename;
return filename.replace(/^marko\/src\//, "marko/dist/");
}

View File

@ -1,172 +0,0 @@
import path from "path";
import { types as t } from "@marko/babel-types";
import { getClientPath } from "lasso-modules-client/transport";
import { parse, parseExpression } from "@babel/parser";
import createFile from "./util/create-file";
import codeFrameError from "./util/code-frame-error";
import codeFrameWarning from "./util/code-frame-warning";
import { getLocRange } from "./util/get-loc";
import checksum from "./util/checksum";
export class Hub {
constructor(filename, code, options) {
this._code = code;
this.options = options;
this.filename = filename;
this.file = createFile(filename, code);
this.lookup = this.options.lookup;
this.macros = Object.create(null);
this.meta = this.file.markoMeta = {
id: checksum(this.getClientPath(this.filename)),
deps: [],
tags: []
};
this._imports = Object.create(null);
}
getCode() {
return this._code;
}
getWhitespaceBefore(pos) {
return (
this._codeAsWhitespace ||
(this._codeAsWhitespace = this._code.replace(/[^\n\r ]/g, " "))
).slice(0, pos);
}
buildError(node, msg) {
return codeFrameError(this.filename, this._code, msg, node.start, node.end);
}
buildWarning(node, msg) {
return codeFrameWarning(this.filename, this._code, msg, node);
}
getClientPath(file) {
return getClientPath(file);
}
resolveRelativePath(filename) {
const dir = path.dirname(this.filename);
let relativePath = path.isAbsolute(filename)
? path.relative(dir, filename)
: filename;
if (/^[^./]/.test(relativePath)) relativePath = `./${relativePath}`;
return relativePath.replace(/^(?:\.{1,2}\/)+node_modules\//, "");
}
importDefault(path, file, nameHint) {
file = remapProductionMarkoBuild(path, file);
const { _imports } = this;
let importDeclaration = _imports[file];
if (!importDeclaration) {
importDeclaration = _imports[file] = this.program.pushContainer(
"body",
t.importDeclaration([], t.stringLiteral(file))
)[0];
}
if (!nameHint) {
return;
}
const specifiers = importDeclaration.get("specifiers");
const specifier = specifiers.find(specifier =>
specifier.isImportDefaultSpecifier()
);
if (!specifier) {
const identifier = path.scope.generateUidIdentifier(nameHint);
importDeclaration.pushContainer(
"specifiers",
t.importDefaultSpecifier(identifier)
);
return identifier;
}
return t.identifier(specifier.node.local.name);
}
importNamed(path, file, name, nameHint = name) {
file = remapProductionMarkoBuild(path, file);
const { _imports } = this;
let importDeclaration = _imports[file];
if (!importDeclaration) {
importDeclaration = _imports[file] = this.program.pushContainer(
"body",
t.importDeclaration([], t.stringLiteral(file))
)[0];
}
const specifiers = importDeclaration.get("specifiers");
const specifier = specifiers.find(
specifier =>
specifier.isImportSpecifier() && specifier.node.imported.name === name
);
if (!specifier) {
const identifier = path.scope.generateUidIdentifier(nameHint);
importDeclaration.pushContainer(
"specifiers",
t.importSpecifier(identifier, t.identifier(name))
);
return identifier;
}
return t.identifier(specifier.node.local.name);
}
addStaticNode(node) {
this.program.pushContainer("body", node);
}
createNode(type, start, end, ...args) {
return {
...t[type](...args),
...getLocRange(this._code, start, end)
};
}
parse(str, start) {
return this._tryParseJS(false, str, start);
}
parseExpression(str, start) {
return this._tryParseJS(true, str, start);
}
_tryParseJS(isExpression, str, start) {
const opts = this.options.jsParseOptions;
str = this.getWhitespaceBefore(start) + str;
try {
return isExpression
? parseExpression(str, opts)
: parse(str, opts).program;
} catch (err) {
let { pos, message } = err;
if (pos) {
throw codeFrameError(
this.filename,
this._code,
message.replace(/ *\(\d+:\d+\)$/, ""),
pos
);
} else {
throw err;
}
}
}
}
function remapProductionMarkoBuild(path, file) {
const {
hub: {
options: { isProduction }
}
} = path;
if (!isProduction) return file;
return file.replace(/^marko\/src\//, "marko/dist/");
}

View File

@ -1,18 +1,18 @@
import { extname, dirname } from "path";
import { Hub } from "./hub";
import { extname } from "path";
import { types as t } from "@marko/babel-types";
import { parse } from "./parser";
import { visitor as migrate } from "./plugins/migrate";
import { visitor as transform } from "./plugins/transform";
import { NodePath, visitors } from "@babel/traverse";
import { buildLookup } from "../taglib";
import traverse, { visitors } from "@babel/traverse";
import markoModules from "../../modules";
import { MarkoFile } from "./file";
export default (api, options) => {
export default (api, markoOptions) => {
api.assertVersion(7);
options.output = options.output || "html";
markoOptions.output = markoOptions.output || "html";
const isProduction = api.env("production");
const translator = options.translator;
const translator = markoOptions.translator;
if (!translator || !translator.visitor) {
throw new Error(
@ -24,57 +24,57 @@ export default (api, options) => {
name: "marko",
parserOverride(code, jsParseOptions) {
const filename = jsParseOptions.sourceFileName;
const hub = new Hub(filename, code, {
...options,
jsParseOptions,
isProduction,
lookup: buildLookup(dirname(filename), translator)
const file = new MarkoFile(filename, code, jsParseOptions, {
...markoOptions,
isProduction
});
// Only run on Marko files.
if (!(extname(filename) === ".marko" || options.allExtensions)) {
return hub.parse(code, 0);
if (!(extname(filename) === ".marko" || markoOptions.allExtensions)) {
return file.parse(code, 0);
}
const nodePath = new NodePath(hub);
nodePath.node = hub.file;
hub.program = nodePath.get("program");
parse(nodePath);
parse(file);
// TODO: this package should be split into 4:
// 1. babel-syntax-marko (removes the need for the _parseOnly option)
// 2. babel-plugin-migrate-marko (removes the need for the _migrateOnly option)
// 3. babel-plugin-transform-marko (only runs transformers without converting Marko nodes to js)
// 4. babel-plugin-translate-marko (runs final translations)
if (!options._parseOnly) {
nodePath.get("program").scope.crawl(); // Initialize bindings.
const rootMigrators = Object.values(hub.lookup.taglibsById)
if (!markoOptions._parseOnly) {
file.path.scope.crawl(); // Initialize bindings.
const rootMigrators = Object.values(file._lookup.taglibsById)
.map(it => it.migratorPath)
.filter(Boolean)
.map(it => markoModules.require(it))
.map(it => (it.default || it)(api, options));
nodePath.traverse(
.map(it => (it.default || it)(api, markoOptions));
traverse(
file.ast,
rootMigrators.length
? visitors.merge(rootMigrators.concat(migrate))
: migrate
: migrate,
file.scope
);
if (!options._migrateOnly) {
const rootTransformers = hub.lookup.merged.transformers
if (!markoOptions._migrateOnly) {
const rootTransformers = file._lookup.merged.transformers
.map(it => markoModules.require(it.path))
.map(it => (it.default || it)(api, options));
nodePath.traverse(
.map(it => (it.default || it)(api, markoOptions));
traverse(
file.ast,
rootTransformers.length
? visitors.merge(rootTransformers.concat(transform))
: transform
: transform,
file.scope
);
nodePath.traverse(translator.visitor);
traverse(file.ast, translator.visitor, file.scope);
}
}
return Object.assign({}, hub.file);
file.ast.markoMeta = file._meta;
return t.cloneDeep(file.ast);
},
post(file) {
pre(file) {
// Attach marko metadata to babel metadata.
file.metadata.marko = file.ast.markoMeta;
}

View File

@ -16,15 +16,14 @@ const htmlTrim = t => htmlTrimStart(htmlTrimEnd(t));
const isAttributeTag = node =>
t.isStringLiteral(node.name) && node.name.value[0] === "@";
export function parse(fileNodePath) {
const { hub } = fileNodePath;
const { filename, htmlParseOptions = {} } = hub;
const { preserveWhitespace } = htmlParseOptions;
const code = hub.getCode();
const getTagBody = () =>
currentTag.get(currentTag.isFile() ? "program" : "body");
export function parse(file) {
const { code } = file;
const { htmlParseOptions = {} } = file._markoOptions;
const pushTagBody = node => getTagBody().pushContainer("body", node);
let currentTag = fileNodePath;
const getTagBody = () =>
currentTag.isProgram() ? currentTag : currentTag.get("body");
let { preserveWhitespace } = htmlParseOptions;
let currentTag = file.path;
let preservingWhitespaceUntil = preserveWhitespace;
let wasSelfClosing = false;
let handledTagName = false;
@ -32,27 +31,27 @@ export function parse(fileNodePath) {
const handlers = {
onDocumentType({ value, pos, endPos }) {
const node = hub.createNode("markoDocumentType", pos, endPos, value);
const node = file.createNode("markoDocumentType", pos, endPos, value);
pushTagBody(node);
/* istanbul ignore next */
onNext = onNext && onNext(node);
},
onDeclaration({ value, pos, endPos }) {
const node = hub.createNode("markoDeclaration", pos, endPos, value);
const node = file.createNode("markoDeclaration", pos, endPos, value);
pushTagBody(node);
/* istanbul ignore next */
onNext = onNext && onNext(node);
},
onComment({ value, pos, endPos }) {
const node = hub.createNode("markoComment", pos, endPos, value);
const node = file.createNode("markoComment", pos, endPos, value);
pushTagBody(node);
onNext = onNext && onNext(node);
},
onCDATA({ value, pos, endPos }) {
const node = hub.createNode("markoCDATA", pos, endPos, value);
const node = file.createNode("markoCDATA", pos, endPos, value);
pushTagBody(node);
onNext = onNext && onNext(node);
},
@ -99,7 +98,7 @@ export function parse(fileNodePath) {
}
const endPos = pos + value.length;
const node = hub.createNode("markoText", pos, endPos, value);
const node = file.createNode("markoText", pos, endPos, value);
const prevBody = getTagBody().node.body;
pushTagBody(node);
onNext && onNext(node);
@ -116,11 +115,14 @@ export function parse(fileNodePath) {
onPlaceholder({ escape, value, withinBody, pos, endPos }) {
if (withinBody) {
const node = hub.createNode(
const node = file.createNode(
"markoPlaceholder",
pos,
endPos,
hub.parseExpression(value, pos + (escape ? 2 /* ${ */ : 3) /* $!{ */),
file.parseExpression(
value,
pos + (escape ? 2 /* ${ */ : 3) /* $!{ */
),
escape
);
@ -131,7 +133,7 @@ export function parse(fileNodePath) {
onScriptlet({ value, line, block, pos, endPos }) {
if (!line && !block) {
throw hub.buildError(
throw file.buildCodeFrameError(
{ start: pos, end: endPos },
"<% scriptlets %> are no longer supported."
);
@ -140,11 +142,11 @@ export function parse(fileNodePath) {
pos -= 1; // Include $.
// Scriptlets are ignored as content and don't call `onNext`.
pushTagBody(
hub.createNode(
file.createNode(
"markoScriptlet",
pos,
endPos,
hub.parse(value, pos + 2 /** Ignores leading `$ ` */).body
file.parse(value, pos + 2 /** Ignores leading `$ ` */).body
)
);
},
@ -154,25 +156,28 @@ export function parse(fileNodePath) {
const tagName = event.tagName || "div";
const [, tagNameExpression] =
/^\$\{([\s\S]*)\}/.exec(tagName) || EMPTY_ARRAY;
const tagDef = !tagNameExpression && hub.lookup.getTag(tagName);
const tagDef = !tagNameExpression && file._lookup.getTag(tagName);
const tagNameStartPos = pos + (event.concise ? 0 : 1); // Account for leading `<`.
handledTagName = true;
if (tagNameExpression === "") {
throw hub.buildError(
throw file.buildCodeFrameError(
{ start: tagNameStartPos + 1, end: tagNameStartPos + 3 },
"Missing expression for <${dynamic}> tag."
);
}
const node = hub.createNode(
const node = file.createNode(
"markoTag",
pos,
endPos,
tagNameExpression
? hub.parseExpression(tagNameExpression, tagNameStartPos + 2 /* ${ */)
: hub.createNode(
? file.parseExpression(
tagNameExpression,
tagNameStartPos + 2 /* ${ */
)
: file.createNode(
"stringLiteral",
tagNameStartPos,
tagNameStartPos + tagName.length,
@ -189,8 +194,8 @@ export function parse(fileNodePath) {
if (parseOptions) {
event.setParseOptions(parseOptions);
if (parseOptions.rootOnly && !currentTag.isFile()) {
throw hub.buildError(
if (parseOptions.rootOnly && !currentTag.isProgram()) {
throw file.buildCodeFrameError(
{ start: pos, end: endPos },
`"${tagName}" tags must be at the root of your Marko template.`
);
@ -233,17 +238,17 @@ export function parse(fileNodePath) {
}
if (!parseOptions.ignoreAttributes) {
currentTag.set("params", parseParams(hub, event.params));
currentTag.set("arguments", parseArguments(hub, event.argument));
currentTag.set("params", parseParams(file, event.params));
currentTag.set("arguments", parseArguments(file, event.argument));
currentTag.set(
"attributes",
parseIDShorthand(
hub,
file,
event.shorthandId,
parseClassnameShorthand(
hub,
file,
event.shorthandClassNames,
parseAttributes(hub, event.attributes, tagNameEndPos)
parseAttributes(file, event.attributes, tagNameEndPos)
)
)
);
@ -285,7 +290,7 @@ export function parse(fileNodePath) {
code[pos + 1] !== "/" &&
!currentTag.get("name").isStringLiteral()
) {
throw hub.buildError(
throw file.buildCodeFrameError(
{ start: pos, end: endPos },
`Invalid ending for dynamic tag, expected "</>".`
);
@ -297,7 +302,7 @@ export function parse(fileNodePath) {
(module.default || module)(tag, t);
}
currentTag = currentTag.parentPath.parentPath;
currentTag = currentTag.parentPath.parentPath || file.path;
},
onfinish() {
@ -306,17 +311,17 @@ export function parse(fileNodePath) {
onError({ message, pos, endPos }) {
if (message.includes("EOF")) endPos = pos;
throw hub.buildError({ start: pos, end: endPos }, message);
throw file.buildCodeFrameError({ start: pos, end: endPos }, message);
}
};
createParser(handlers, {
isOpenTagOnly(name) {
const { parseOptions = EMPTY_OBJECT } =
hub.lookup.getTag(name) || EMPTY_OBJECT;
file._lookup.getTag(name) || EMPTY_OBJECT;
return parseOptions.openTagOnly;
},
ignoreNonstandardStringPlaceholders: true,
...htmlParseOptions
}).parse(code, filename);
}).parse(code, file.opts.filename);
}

View File

@ -28,10 +28,13 @@ export const visitor = {
};
function getMigratorsForTag(path) {
const { hub } = path;
const { lookup } = hub;
const {
hub: { file }
} = path;
const { _lookup } = file;
const tagName = path.get("name.value").node;
const MIGRATOR_CACHE = (lookup.MIGRATOR_CACHE = lookup.MIGRATOR_CACHE || {});
const MIGRATOR_CACHE = (_lookup.MIGRATOR_CACHE =
_lookup.MIGRATOR_CACHE || {});
let migrators = MIGRATOR_CACHE[tagName];
@ -40,7 +43,7 @@ function getMigratorsForTag(path) {
migrators = MIGRATOR_CACHE[tagName] = [
...(tagDef ? tagDef.migratorPaths : []),
...(lookup.getTag("*") || { migratorPaths: [] }).migratorPaths
...(_lookup.getTag("*") || { migratorPaths: [] }).migratorPaths
].map(path => markoModules.require(path));
}

View File

@ -8,7 +8,7 @@ import { enter, exit } from "../util/plugin-hooks";
*/
export const visitor = {
Program(path) {
path.hub._componentDefIdentifier = path.scope.generateUidIdentifier(
path.hub.file._componentDefIdentifier = path.scope.generateUidIdentifier(
"component"
);
},
@ -35,11 +35,13 @@ export const visitor = {
};
function getTransformersForTag(path) {
const { hub } = path;
const { lookup } = hub;
const {
hub: { file }
} = path;
const { _lookup } = file;
const tagName = path.get("name.value").node || "*";
const TRANSFORMER_CACHE = (lookup.TRANSFORMER_CACHE =
lookup.TRANSFORMER_CACHE || {});
const TRANSFORMER_CACHE = (_lookup.TRANSFORMER_CACHE =
_lookup.TRANSFORMER_CACHE || {});
let transformers = TRANSFORMER_CACHE[tagName];
@ -51,7 +53,9 @@ function getTransformersForTag(path) {
: []
)
.concat(
Object.values((lookup.getTag("*") || { transformers: [] }).transformers)
Object.values(
(_lookup.getTag("*") || { transformers: [] }).transformers
)
)
.sort(comparePriority)
.map(({ path }) => markoModules.require(path));

View File

@ -1,14 +0,0 @@
import { relative } from "path";
import { codeFrameColumns } from "@babel/code-frame";
import { getLoc } from "./get-loc";
const cwd = process.cwd();
export default (filename = "", code, msg, startPos, endPos) => {
const start = getLoc(code, startPos);
const end = endPos != null && getLoc(code, endPos);
const frame = codeFrameColumns(code, { start, end }, { highlightCode: true });
const position = `(${start.line},${start.column})`;
return new SyntaxError(
`${relative(cwd, filename)}${position}: ${msg}\n${frame}`
);
};

View File

@ -1,25 +0,0 @@
import { relative } from "path";
import { codeFrameColumns } from "@babel/code-frame";
import { getLoc } from "./get-loc";
import complain from "complain";
const cwd = process.cwd();
export default (filename = "", code, msg, node) => {
const start = getLoc(code, node.start);
const end = node.end != null && getLoc(code, node.end);
const frame = codeFrameColumns(code, { start, end }, { highlightCode: true });
const position = `(${start.line},${start.column})`;
const location = node && node.pos;
const options = { location };
if (location != null) {
options.location = position;
} else {
options.location = filename;
}
return complain(
`${relative(cwd, filename)}${position}: ${msg}\n${frame}`,
options
);
};

View File

@ -1,21 +0,0 @@
import { getLoc } from "./get-loc";
export default (filename, code) => {
const opts = { filename };
const start = { line: 0, column: 0 };
const end = getLoc(code, code.length);
const loc = { start, end, loc: { start, end } };
return {
type: "File",
code,
opts,
...loc,
program: {
type: "Program",
sourceType: "module",
...loc,
body: [],
directives: []
}
};
};

View File

@ -1,6 +1,6 @@
export default (hub, details) => {
export default (file, details) => {
if (details) {
return hub.parseExpression(`_(${details.value})`, details.pos - 1)
return file.parseExpression(`_(${details.value})`, details.pos - 1)
.arguments;
}
};

View File

@ -1,8 +1,8 @@
import { types as t } from "@marko/babel-types";
import parseArguments from "./parse-arguments";
export default (hub, attributes, startPos) => {
const code = hub.getCode();
export default (file, attributes, startPos) => {
const code = file.code;
let attrEndPos = startPos;
return attributes.map(attr => {
@ -17,10 +17,10 @@ export default (hub, attributes, startPos) => {
attrEndPos = attrStartPos + attrExpression.length;
const value = hub.parseExpression(attrExpression, attrStartPos + 3);
const value = file.parseExpression(attrExpression, attrStartPos + 3);
// TODO: Inline merge object literals.
return hub.createNode(
return file.createNode(
"markoSpreadAttribute",
attrStartPos,
attrEndPos,
@ -41,20 +41,20 @@ export default (hub, attributes, startPos) => {
attrEndPos = attr.endPos;
const valueStart = attr.pos + 1; // Add one to account for "=".
const rawValue = code.slice(valueStart, attrEndPos); // We use the raw value to ignore things like non standard placeholders.
value = hub.parseExpression(rawValue, valueStart);
value = file.parseExpression(rawValue, valueStart);
} else {
attrEndPos = attr.argument ? attr.argument.endPos + 1 : attr.endPos;
value = t.booleanLiteral(true);
}
return hub.createNode(
return file.createNode(
"markoAttribute",
attrStartPos,
attrEndPos,
name,
value,
modifier,
parseArguments(hub, attr.argument)
parseArguments(file, attr.argument)
);
});
};

View File

@ -1,6 +1,6 @@
import { types as t } from "@marko/babel-types";
export default (hub, shorthands, attributes) => {
export default (file, shorthands, attributes) => {
if (!shorthands) {
return attributes;
}
@ -9,8 +9,8 @@ export default (hub, shorthands, attributes) => {
const classParts = shorthands.map(({ rawParts }) => {
const nodes = rawParts.map(part =>
part.expression
? hub.parseExpression(part.expression, part.pos)
: hub.createNode("stringLiteral", part.pos, part.endPos, part.text)
? file.parseExpression(part.expression, part.pos)
: file.createNode("stringLiteral", part.pos, part.endPos, part.text)
);
if (nodes.length === 1) {
@ -27,7 +27,7 @@ export default (hub, shorthands, attributes) => {
const combinedStartPos = shorthands[0].rawParts[0].pos;
const lastParts = shorthands[shorthands.length - 1].rawParts;
const combinedEndPos = lastParts[lastParts.length - 1].endPos;
shorthandNode = hub.createNode(
shorthandNode = file.createNode(
"stringLiteral",
combinedStartPos,
combinedEndPos,

View File

@ -1,19 +1,22 @@
import { types as t } from "@marko/babel-types";
export default (hub, shorthand, attributes) => {
export default (file, shorthand, attributes) => {
if (!shorthand) {
return attributes;
}
const idAttr = attributes.find(({ name }) => name === "id");
if (idAttr) {
throw hub.buildError(idAttr, "Cannot have shorthand id and id attribute.");
throw file.buildCodeFrameError(
idAttr,
"Cannot have shorthand id and id attribute."
);
}
const idParts = shorthand.rawParts.map(part =>
part.expression
? hub.parseExpression(part.expression, part.pos)
: hub.createNode("stringLiteral", part.pos, part.endPos, part.text)
? file.parseExpression(part.expression, part.pos)
: file.createNode("stringLiteral", part.pos, part.endPos, part.text)
);
attributes.push(

View File

@ -1,5 +1,5 @@
export default (hub, details) => {
export default (file, details) => {
if (details) {
return hub.parseExpression(`(${details.value})=>{}`, details.pos).params;
return file.parseExpression(`(${details.value})=>{}`, details.pos).params;
}
};

View File

@ -3,9 +3,11 @@ import translateVDOM from "./index[vdom]";
export default function(path) {
const {
hub: { options }
hub: {
file: { _markoOptions }
}
} = path;
if (options.output === "html") {
if (_markoOptions.output === "html") {
translateHTML(path);
} else {
translateVDOM(path);

View File

@ -2,7 +2,7 @@ import { types as t } from "@marko/babel-types";
export default function(path) {
const {
hub,
hub: { file },
node: {
body: { body }
}
@ -36,7 +36,10 @@ export default function(path) {
return undefined;
}
throw hub.buildError(prop, "Unsupported class property on component.");
throw file.buildCodeFrameError(
prop,
"Unsupported class property on component."
);
})
.filter(Boolean);
@ -55,6 +58,6 @@ export default function(path) {
onCreateMethod.body.body.unshift(...classProperties);
}
hub.inlineComponentClass = t.objectExpression(objectProperties);
file._inlineComponentClass = t.objectExpression(objectProperties);
path.remove();
}

View File

@ -3,9 +3,11 @@ import translateVDOM from "./index[vdom]";
export default function(path) {
const {
hub: { options }
hub: {
file: { _markoOptions }
}
} = path;
if (options.output === "html") {
if (_markoOptions.output === "html") {
translateHTML(path);
} else {
translateVDOM(path);

View File

@ -3,9 +3,11 @@ import translateVDOM from "./index[vdom]";
export default function(path) {
const {
hub: { options }
hub: {
file: { _markoOptions }
}
} = path;
if (options.output === "html") {
if (_markoOptions.output === "html") {
translateHTML(path);
} else {
translateVDOM(path);

View File

@ -3,9 +3,11 @@ import translateVDOM from "./index[vdom]";
export default function(path) {
const {
hub: { options }
hub: {
file: { _markoOptions }
}
} = path;
if (options.output === "html") {
if (_markoOptions.output === "html") {
translateHTML(path);
} else {
translateVDOM(path);

View File

@ -26,11 +26,13 @@ export const visitor = {
MarkoComment,
Program: {
enter(path) {
const { hub } = path;
const {
hub: { file }
} = path;
if (hub.moduleCode) {
if (file._moduleCode) {
path.get("body").forEach(bodyItemPath => bodyItemPath.remove());
hub.moduleCode.forEach(node => path.pushContainer("body", node));
file._moduleCode.forEach(node => path.pushContainer("body", node));
return path.skip();
}
@ -44,55 +46,59 @@ export const visitor = {
childPath.remove();
});
hub._renderBlock = renderBlock;
file._renderBlock = renderBlock;
},
exit(path) {
const { hub } = path;
const { options, meta, inlineComponentClass } = hub;
const {
hub: { file }
} = path;
const { _markoOptions, _meta, _inlineComponentClass } = file;
const {
styleFile,
packageFile,
componentFile,
componentBrowserFile
} = getComponentFiles(path);
const isHTML = options.output === "html";
const isHTML = _markoOptions.output === "html";
let isSplit = false;
let isImplicit = !hub._hasTagParams;
let isImplicit = !file._hasTagParams;
if (packageFile) {
meta.deps.unshift(packageFile);
_meta.deps.unshift(packageFile);
}
if (styleFile) {
meta.deps.unshift(styleFile);
_meta.deps.unshift(styleFile);
}
if (componentFile || inlineComponentClass) {
if (componentFile || _inlineComponentClass) {
isImplicit = false;
meta.component = hub.filename;
_meta.component = file.opts.filename;
}
if (componentBrowserFile) {
isImplicit = false;
isSplit = true;
meta.component = componentBrowserFile;
_meta.component = componentBrowserFile;
}
meta.component =
meta.component && hub.resolveRelativePath(meta.component);
meta.deps = meta.deps.map(file =>
typeof file === "string" ? hub.resolveRelativePath(file) : file
_meta.component =
_meta.component && file.resolveRelativePath(_meta.component);
_meta.deps = _meta.deps.map(filename =>
typeof filename === "string"
? file.resolveRelativePath(filename)
: filename
);
const renderBlock = hub._renderBlock;
const renderBlock = file._renderBlock;
const componentClass =
(componentFile &&
hub.importDefault(
file.importDefault(
path,
hub.resolveRelativePath(componentFile),
file.resolveRelativePath(componentFile),
"marko_component"
)) ||
inlineComponentClass ||
_inlineComponentClass ||
t.objectExpression([]);
const componentIdentifier = path.scope.generateUidIdentifier(
@ -104,7 +110,7 @@ export const visitor = {
const templateIdentifier = path.scope.generateUidIdentifier(
"marko_template"
);
const rendererIdentifier = hub.importDefault(
const rendererIdentifier = file.importDefault(
path,
"marko/src/runtime/components/renderer",
"marko_renderer"
@ -117,9 +123,9 @@ export const visitor = {
templateIdentifier,
t.identifier("meta")
);
const componentId = meta.id;
const componentId = _meta.id;
if (options.writeVersionComment) {
if (_markoOptions.writeVersionComment) {
path.addComment(
"leading",
` Compiled using marko@${version} - DO NOT EDIT`,
@ -137,7 +143,11 @@ export const visitor = {
t.variableDeclarator(
templateIdentifier,
t.callExpression(
hub.importNamed(path, `marko/src/runtime/${options.output}`, "t"),
file.importNamed(
path,
`marko/src/runtime/${_markoOptions.output}`,
"t"
),
[t.identifier("__filename")]
)
)
@ -153,7 +163,7 @@ export const visitor = {
isHTML
? componentIdString
: t.callExpression(
hub.importNamed(
file.importNamed(
path,
"marko/src/runtime/components/registry-browser",
"r",
@ -164,9 +174,9 @@ export const visitor = {
t.arrowFunctionExpression(
[],
isSplit
? hub.importDefault(
? file.importDefault(
path,
hub.resolveRelativePath(componentBrowserFile),
file.resolveRelativePath(componentBrowserFile),
"marko_split_component"
)
: templateIdentifier
@ -206,7 +216,7 @@ export const visitor = {
[
t.identifier("input"),
t.identifier("out"),
hub._componentDefIdentifier,
file._componentDefIdentifier,
t.identifier("component"),
t.identifier("state")
],
@ -228,7 +238,7 @@ export const visitor = {
"=",
t.memberExpression(templateIdentifier, t.identifier("Component")),
t.callExpression(
hub.importDefault(
file.importDefault(
path,
"marko/src/runtime/components/defineComponent",
"marko_defineComponent"
@ -240,37 +250,34 @@ export const visitor = {
);
}
if (options.meta !== false) {
if (_markoOptions.meta !== false) {
const metaObject = t.objectExpression([
t.objectProperty(t.identifier("id"), componentTypeIdentifier)
]);
if (meta.component) {
if (_meta.component) {
metaObject.properties.push(
t.objectProperty(
t.identifier("component"),
t.stringLiteral(meta.component)
t.stringLiteral(_meta.component)
)
);
}
if (meta.deps.length) {
if (_meta.deps.length) {
metaObject.properties.push(
t.objectProperty(
t.identifier("deps"),
hub.parseExpression(
JSON.stringify(meta.deps),
hub.getCode().length
)
file.parseExpression(JSON.stringify(_meta.deps), file.code.length)
)
);
}
if (meta.tags.length) {
if (_meta.tags.length) {
metaObject.properties.push(
t.objectProperty(
t.identifier("tags"),
t.arrayExpression(meta.tags.map(tag => t.stringLiteral(tag)))
t.arrayExpression(_meta.tags.map(tag => t.stringLiteral(tag)))
)
);
}

View File

@ -3,9 +3,11 @@ import translateVDOM from "./index[vdom]";
export default function(path) {
const {
hub: { options }
hub: {
file: { _markoOptions }
}
} = path;
if (options.output === "html") {
if (_markoOptions.output === "html") {
translateHTML(path);
} else {
translateVDOM(path);

View File

@ -27,7 +27,10 @@ const ESCAPE_TYPES = {
};
export default function(path) {
const { node, hub } = path;
const {
node,
hub: { file }
} = path;
const { confident, value: computed } = path.get("value").evaluate();
let { escape, value } = node;
@ -39,20 +42,20 @@ export default function(path) {
? t.stringLiteral(escapeType.fn(computed))
: t.callExpression(
escapeType.name
? hub.importNamed(
? file.importNamed(
path,
escapeType.module,
escapeType.name,
escapeType.alias
)
: hub.importDefault(path, escapeType.module, escapeType.alias),
: file.importDefault(path, escapeType.module, escapeType.alias),
[value]
);
} else {
value = confident
? t.stringLiteral(toString(computed))
: t.callExpression(
hub.importDefault(
file.importDefault(
path,
"marko/src/runtime/helpers/to-string",
"marko_to_string"

View File

@ -5,7 +5,9 @@ import withPreviousLocation from "../../../util/with-previous-location";
export default {
exit(tag, _, value) {
const { hub } = tag;
const {
hub: { file }
} = tag;
if (!isNativeTag(tag)) return;
if (value.isStringLiteral()) return;
@ -16,7 +18,7 @@ export default {
? t.stringLiteral(classToString(computed) || "")
: withPreviousLocation(
t.callExpression(
hub.importDefault(
file.importDefault(
tag,
"marko/src/runtime/helpers/class-value",
"marko_class_merge"

View File

@ -5,7 +5,9 @@ import withPreviousLocation from "../../../util/with-previous-location";
export default {
exit(tag, _, value) {
const { hub } = tag;
const {
hub: { file }
} = tag;
if (value.isStringLiteral()) return;
if (!isNativeTag(tag)) return;
@ -15,7 +17,7 @@ export default {
confident
? t.stringLiteral(styleToString(computed) || "")
: t.callExpression(
hub.importDefault(
file.importDefault(
tag,
"marko/src/runtime/helpers/style-value",
"marko_style_merge"

View File

@ -8,11 +8,13 @@ const attachedDetachedLoaded = new WeakSet();
export default {
enter(attr) {
const { hub } = attr;
const {
hub: { file }
} = attr;
const tag = attr.parentPath;
const value = attr.get("value");
const { name, arguments: args } = attr.node;
const isVDOM = hub.options.output !== "html";
const isVDOM = file._markoOptions.output !== "html";
if (execModifiersAndDirectives("enter", tag, attr, value)) {
return;
@ -60,10 +62,10 @@ export default {
if (isVDOM) {
if (eventName === "attach" || eventName === "detach") {
if (!attachedDetachedLoaded.has(hub)) {
if (!attachedDetachedLoaded.has(file)) {
// Pull in helper for element attach/detach;
attachedDetachedLoaded.add(hub);
hub.importDefault(
attachedDetachedLoaded.add(file);
file.importDefault(
tag,
"marko/src/runtime/components/attach-detach"
);

View File

@ -7,18 +7,21 @@ const hasMonkeyPatch = new WeakSet();
*/
export default {
exit(tag, attr) {
const { node, hub } = tag;
const {
node,
hub: { file }
} = tag;
const { properties } = node;
const isVDOM = hub.options.output !== "html";
const isVDOM = file._markoOptions.output !== "html";
let prop = properties.find(({ key: { name } }) => name === "noupdate");
if (!prop) {
prop = t.objectProperty(t.identifier("noupdate"), t.arrayExpression([]));
properties.push(prop);
if (isVDOM && !hasMonkeyPatch.has(hub)) {
hasMonkeyPatch.add(hub);
hub.importDefault(tag, "marko/src/runtime/vdom/preserve-attrs");
if (isVDOM && !hasMonkeyPatch.has(file)) {
hasMonkeyPatch.add(file);
file.importDefault(tag, "marko/src/runtime/vdom/preserve-attrs");
}
}

View File

@ -3,11 +3,16 @@ import withPreviousLocation from "../../../util/with-previous-location";
export default {
exit(tag, _, value) {
const { hub } = tag;
const {
hub: { file }
} = tag;
value.replaceWith(
withPreviousLocation(
t.callExpression(
t.memberExpression(hub._componentDefIdentifier, t.identifier("elId")),
t.memberExpression(
file._componentDefIdentifier,
t.identifier("elId")
),
[value.node]
),
value.node

View File

@ -8,8 +8,11 @@ import withPreviousLocation from "../util/with-previous-location";
const TAG_FILE_ENTRIES = ["template", "renderer"];
export default function(path) {
const { hub, node } = path;
const { meta, options } = hub;
const {
hub: { file },
node
} = path;
const { _meta, _markoOptions } = file;
const { name, key, isNullable } = node;
assertNoArgs(path);
@ -19,10 +22,10 @@ export default function(path) {
if (t.isStringLiteral(name)) {
const tagDef = getTagDef(path);
const tagName = name.value;
const relativePath = tagDef && resolveRelativePath(hub, tagDef);
const relativePath = tagDef && resolveRelativePath(file, tagDef);
if (!relativePath) {
if (options.ignoreUnrecognizedTags) {
if (_markoOptions.ignoreUnrecognizedTags) {
return nativeTag(path);
}
@ -33,10 +36,10 @@ export default function(path) {
);
}
tagIdentifier = hub.importDefault(path, relativePath, tagName);
tagIdentifier = file.importDefault(path, relativePath, tagName);
if (!meta.tags.includes(relativePath)) {
meta.tags.push(relativePath);
if (!_meta.tags.includes(relativePath)) {
_meta.tags.push(relativePath);
}
} else {
tagIdentifier = name;
@ -46,7 +49,7 @@ export default function(path) {
const customTagRenderCall = withPreviousLocation(
t.expressionStatement(
t.callExpression(
hub.importDefault(
file.importDefault(
path,
"marko/src/runtime/helpers/render-tag",
"marko_tag"
@ -56,7 +59,7 @@ export default function(path) {
// TODO: this could be left as null if we froze input mutations and used a default object in the runtime.
t.isNullLiteral(foundAttrs) ? t.objectExpression([]) : foundAttrs,
t.identifier("out"),
hub._componentDefIdentifier,
file._componentDefIdentifier,
key,
...buildEventHandlerArray(path)
]
@ -99,9 +102,9 @@ export default function(path) {
}
}
function resolveRelativePath(hub, tagDef) {
function resolveRelativePath(file, tagDef) {
for (const entry of TAG_FILE_ENTRIES) {
if (!tagDef[entry]) continue;
return hub.resolveRelativePath(tagDef[entry]);
return file.resolveRelativePath(tagDef[entry]);
}
}

View File

@ -8,7 +8,10 @@ import customTag from "./custom-tag";
const HANDLE_BINDINGS = ["module", "var", "let", "const"];
export default function(path) {
const { node, hub } = path;
const {
node,
hub: { file }
} = path;
const { key, arguments: args, properties: tagProperties } = node;
const name = path.get("name");
@ -59,7 +62,7 @@ export default function(path) {
}
const dynamicTagRenderCall = t.callExpression(
hub.importDefault(
file.importDefault(
path,
`marko/src/runtime/helpers/dynamic-tag`,
"marko_dynamic_tag"
@ -73,7 +76,7 @@ export default function(path) {
tagProperties.length
? t.objectExpression(tagProperties)
: t.nullLiteral(),
hub._componentDefIdentifier,
file._componentDefIdentifier,
key,
...buildEventHandlerArray(path)
]

View File

@ -45,7 +45,7 @@ export default {
}
}
if (path.hub.options.ignoreUnrecognizedTags && !tagDef) {
if (path.hub.file._markoOptions.ignoreUnrecognizedTags && !tagDef) {
findAttributeTags(path).forEach(child => {
child.set(
"name",

View File

@ -7,16 +7,18 @@ import {
} from "@marko/babel-utils";
export default function(path) {
const { hub } = path;
const { options } = hub;
const {
hub: { file }
} = path;
const { _markoOptions } = file;
if (!options.ignoreUnrecognizedTags) {
if (!_markoOptions.ignoreUnrecognizedTags) {
assertNoArgs(path);
assertNoParams(path);
assertNoAttributeTags(path);
}
if (options.output === "html") {
if (_markoOptions.output === "html") {
nativeTagHtml(path);
} else {
nativeTagVdom(path);

View File

@ -18,7 +18,7 @@ export default function(path, attrs) {
for (let i = 0; i < attrs.length; i++) {
const attr = attrs[i];
const {
hub,
hub: { file },
node: { name, value }
} = attr;
@ -56,7 +56,7 @@ export default function(path, attrs) {
expressions.push(
t.callExpression(
hub.importDefault(
file.importDefault(
attr,
"marko/src/runtime/html/helpers/attr",
"marko_attr"
@ -69,7 +69,7 @@ export default function(path, attrs) {
quasis.push(curString);
if (hasSpread) {
return t.callExpression(
path.hub.importDefault(
path.hub.file.importDefault(
path,
"marko/src/runtime/html/helpers/attrs",
"marko_attrs"

View File

@ -14,7 +14,10 @@ const EMPTY_OBJECT = {};
* Translates the html streaming version of a standard html element.
*/
export default function(path) {
const { hub, node } = path;
const {
hub: { file },
node
} = path;
const {
name,
body: { body },
@ -29,7 +32,7 @@ export default function(path) {
const { parseOptions = EMPTY_OBJECT } = tagDef;
if (parseOptions.import) {
// TODO: the taglib should be updated to support this as a top level option.
hub.meta.deps.push(resolve(tagDef.dir, parseOptions.import));
file._meta.deps.push(resolve(tagDef.dir, parseOptions.import));
}
}
@ -51,7 +54,7 @@ export default function(path) {
t.stringLiteral(`on${eventName}`),
t.callExpression(
t.memberExpression(
hub._componentDefIdentifier,
file._componentDefIdentifier,
t.identifier("d")
),
delegateArgs
@ -62,22 +65,22 @@ export default function(path) {
);
}
const isHTML = hub.options.output === "html";
const isHTML = file._markoOptions.output === "html";
let dataMarko = t.stringLiteral("");
if (isHTML) {
const componentFiles = getComponentFiles(path);
const isSplit = Boolean(componentFiles.componentBrowserFile);
const isImplicit = Boolean(
!hub.inlineComponentClass &&
!file._inlineComponentClass &&
!componentFiles.componentFile &&
!hub._hasTagParams
!file._hasTagParams
);
const needsDataMarkoAttr = isSplit || isImplicit || isPreserved(path);
if (needsDataMarkoAttr) {
const dataMarkoArgs = [t.identifier("out"), hub._componentDefIdentifier];
const dataMarkoArgs = [t.identifier("out"), file._componentDefIdentifier];
if (tagProperties.length) {
// TODO we should pre evaluate this if it is static.
@ -89,12 +92,12 @@ export default function(path) {
dataMarkoArgs.push(t.numericLiteral(0));
}
dataMarkoArgs.push(path.get("key").node, hub._componentDefIdentifier);
dataMarkoArgs.push(path.get("key").node, file._componentDefIdentifier);
}
if (dataMarkoArgs.length > 2) {
dataMarko = t.callExpression(
hub.importDefault(
file.importDefault(
path,
"marko/src/runtime/html/helpers/data-marko",
"marko_props"

View File

@ -19,7 +19,11 @@ const MAYBE_SVG = {
* Translates the html streaming version of a standard html element.
*/
export default function(path) {
const { hub, node, parent } = path;
const {
hub: { file },
node,
parent
} = path;
const {
name,
key,
@ -51,7 +55,7 @@ export default function(path) {
attrsObj.properties.some(t.isSpreadElement)
) {
attrsObj = t.callExpression(
hub.importDefault(
file.importDefault(
path,
"marko/src/runtime/vdom/helpers/attrs",
"marko_attrs"
@ -88,7 +92,7 @@ export default function(path) {
t.stringLiteral(`on${eventName}`),
t.callExpression(
t.memberExpression(
hub._componentDefIdentifier,
file._componentDefIdentifier,
t.identifier("d")
),
delegateArgs
@ -115,7 +119,7 @@ export default function(path) {
node.runtimeFlags |= FLAGS.IS_CUSTOM_ELEMENT;
if (parseOptions.import) {
// TODO: the taglib should be updated to support this as a top level option.
hub.meta.deps.push(resolve(tagDef.dir, parseOptions.import));
file._meta.deps.push(resolve(tagDef.dir, parseOptions.import));
}
} else if (
htmlType === "svg" ||

View File

@ -4,7 +4,10 @@ import { getTagDef } from "@marko/babel-utils";
const EMPTY_ARR = [];
export function getAttrs(path, noCamel, skipRenderBody) {
const { node, hub } = path;
const {
node,
hub: { file }
} = path;
const {
attributes,
body: { body },
@ -66,8 +69,8 @@ export function getAttrs(path, noCamel, skipRenderBody) {
path.insertBefore(body);
} else {
if (node.params) {
if (!hub._hasTagParams && !isIgnoredTagParams(path)) {
hub._hasTagParams = true;
if (!file._hasTagParams && !isIgnoredTagParams(path)) {
file._hasTagParams = true;
}
}

View File

@ -1,6 +1,8 @@
export function enter(path) {
const {
hub: { macros },
hub: {
file: { _macros }
},
node
} = path;
const attributes = path.get("attributes");
@ -28,11 +30,11 @@ export function enter(path) {
const name = nameAttrValue.node.value;
if (macros[name]) {
if (_macros[name]) {
throw nameAttr.buildCodeFrameError(
`A macro with the name "${name}" already exists.`
);
}
node._macroId = macros[name] = path.scope.generateUidIdentifier(name);
node._macroId = _macros[name] = path.scope.generateUidIdentifier(name);
}

View File

@ -4,7 +4,10 @@ import getComponentFiles from "../../util/get-component-files";
const SEEN_INLINE_CLASS = new WeakSet();
export default function(path) {
const { node, hub } = path;
const {
node,
hub: { file }
} = path;
const { rawValue: code, start } = node;
if (getComponentFiles(path).componentFile) {
@ -15,7 +18,7 @@ export default function(path) {
);
}
if (SEEN_INLINE_CLASS.has(hub)) {
if (SEEN_INLINE_CLASS.has(file)) {
throw path
.get("name")
.buildCodeFrameError(
@ -23,14 +26,17 @@ export default function(path) {
);
}
const parsed = hub.parseExpression(code, start);
const parsed = file.parseExpression(code, start);
if (parsed.id) {
throw hub.buildError(parsed.id, "Component class cannot have a name.");
throw file.buildCodeFrameError(
parsed.id,
"Component class cannot have a name."
);
}
if (parsed.superClass) {
throw hub.buildError(
throw file.buildCodeFrameError(
parsed.superClass,
"Component class cannot have a super class."
);
@ -40,12 +46,12 @@ export default function(path) {
prop => t.isClassMethod(prop) && prop.kind === "constructor"
);
if (constructorProp) {
throw hub.buildError(
throw file.buildCodeFrameError(
constructorProp.key,
"The constructor method should not be used for a component, use onCreate instead."
);
}
SEEN_INLINE_CLASS.add(hub);
SEEN_INLINE_CLASS.add(file);
path.replaceWith(t.markoClass(parsed.body));
}

View File

@ -1,6 +1,9 @@
export default function(path) {
const { node, hub } = path;
const {
node,
hub: { file }
} = path;
const { rawValue, start } = node;
const [exportNode] = hub.parse(rawValue, start).body;
const [exportNode] = file.parse(rawValue, start).body;
path.replaceWith(exportNode);
}

View File

@ -1,6 +1,9 @@
export default function(path) {
const { node, hub } = path;
const {
node,
hub: { file }
} = path;
const { rawValue, start } = node;
const [importNode] = hub.parse(rawValue, start).body;
const [importNode] = file.parse(rawValue, start).body;
path.replaceWith(importNode);
}

View File

@ -6,14 +6,14 @@ const startOffset = "module-code".length;
export default function parse(path) {
const {
hub,
hub: { file },
node: { rawValue, start }
} = path;
const dirname = nodePath.dirname(hub.filename);
const dirname = nodePath.dirname(file.opts.filename);
const relativeRequire = entry =>
markoModules.require(resolveFrom(dirname, entry));
const fn = eval(rawValue.slice(startOffset));
const source = fn(relativeRequire);
const program = hub.parse(source, start + startOffset);
hub.moduleCode = program.body;
const program = file.parse(source, start + startOffset);
file._moduleCode = program.body;
}

View File

@ -1,11 +1,14 @@
import { types as t } from "@marko/babel-types";
export default function(path) {
const { node, hub } = path;
const {
node,
hub: { file }
} = path;
const { rawValue } = node;
const code = rawValue.replace(/^static\s*/, "").trim();
const start = node.start + (rawValue.length - code.length);
let { body } = hub.parse(code, start);
let { body } = file.parse(code, start);
if (body.length === 1 && t.isBlockStatement(body[0])) {
body = body[0].body;
}

View File

@ -12,7 +12,7 @@ export function exit(path) {
} else if (args.length > 1) {
const { start } = args[1].node;
const { end } = args[args.length - 1].node;
throw path.hub.buildError(
throw path.hub.file.buildCodeFrameError(
{ start, end },
'You can only pass one argument to the "<await>" tag.'
);

View File

@ -1,7 +1,7 @@
import { types as t } from "@marko/babel-types";
export function exit(path) {
if (path.hub.options.output === "html") {
if (path.hub.file._markoOptions.output === "html") {
const body = path.get("body");
body.pushContainer("body", [

View File

@ -1,5 +1,5 @@
export function exit(path) {
if (path.hub.options.output !== "html") {
if (path.hub.file._markoOptions.output !== "html") {
path.remove();
}
}

View File

@ -6,12 +6,11 @@ import {
import write from "../../util/html-out-write";
export function enter(path) {
const { hub } = path;
assertNoArgs(path);
assertNoParams(path);
assertNoAttributes(path);
if (hub.options.output === "html") {
if (path.hub.file._markoOptions.output === "html") {
path.replaceWithMultiple([write`<!--`, ...path.node.body.body, write`-->`]);
} else {
path.remove();

View File

@ -4,7 +4,9 @@ import { types as t } from "@marko/babel-types";
import { assertNoParams, assertNoAttributes } from "@marko/babel-utils";
export function enter(path) {
const { hub } = path;
const {
hub: { file }
} = path;
assertNoParams(path);
assertNoAttributes(path);
@ -26,7 +28,7 @@ export function enter(path) {
);
}
const dir = nodePath.dirname(hub.filename);
const dir = nodePath.dirname(file.opts.filename);
const fullPath = nodePath.resolve(dir, content.node.value);
try {

View File

@ -1,15 +1,18 @@
import { basename } from "path";
export function exit(path) {
const { hub, node } = path;
const {
hub: { file },
node
} = path;
const { _styleType: type, _styleCode: code } = node;
if (!type) {
return;
}
const base = basename(hub.filename);
hub.meta.deps.push({
const base = basename(file.opts.filename);
file._meta.deps.push({
type,
code: code.trim(),
path: `./${base}`,

View File

@ -2,10 +2,7 @@ import translateHTML from "./index[html]";
import translateVDOM from "./index[vdom]";
export default function(path) {
const {
hub: { options }
} = path;
if (options.output === "html") {
if (path.hub.file._markoOptions.output === "html") {
translateHTML(path);
} else {
translateVDOM(path);

View File

@ -8,7 +8,7 @@ export default function getComponentFiles({ hub }) {
return CACHE.get(hub);
}
const { filename } = hub;
const { filename } = hub.file.opts;
const ext = path.extname(filename);
const dirname = path.dirname(filename);
const dirFiles = fs.readdirSync(dirname).sort();

View File

@ -1,4 +1,4 @@
packages/translator-default/test/fixtures/error-class-private-properties/template.marko: packages/translator-default/test/fixtures/error-class-private-properties/template.marko(2,3): Unknown PrivateName "#x"
packages/translator-default/test/fixtures/error-class-private-properties/template.marko: Unknown PrivateName "#x"
1 | class {
> 2 | #x = 1;
| ^^