Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
// Split the text node content arround expression and create node for each
const tokenizedContent = rawText.split(EXPRESSION_RE);
for (const token of tokenizedContent) {
// Don't create nodes for emtpy strings
if (!token.length) {
continue;
}
let value;
if (isExpression(token)) {
try {
value = parseTemplateExpression(parent, token);
} catch (error) {
addDiagnostic(
normalizeToDiagnostic(
ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR,
error,
{
location: normalizeLocation(location),
}
)
);
return;
}
} else {
value = decodeTextContent(token);
}
const textNode = createText(node, value);
textNode.parent = parent;
export function compileToFunction(source: string): Function {
const options = mergeConfig({});
options.format = 'function';
const state = new State(source, options);
const parsingResults = parseTemplate(source, state);
for (const warning of parsingResults.warnings) {
if (warning.level === DiagnosticLevel.Error) {
throw CompilerError.from(warning);
} else if (warning.level === DiagnosticLevel.Warning) {
/* eslint-disable-next-line no-console */
console.warn(warning.message);
} else {
/* eslint-disable-next-line no-console */
console.log(warning.message);
}
}
if (!parsingResults.root) {
throw generateCompilerError(TemplateErrors.INVALID_TEMPLATE);
}
const { code } = generate(parsingResults.root, state);
return new Function(TEMPLATE_MODULES_PARAMETER, code);
}
export function compileToFunction(source: string): Function {
const options = mergeConfig({});
options.format = 'function';
const state = new State(source, options);
const parsingResults = parseTemplate(source, state);
for (const warning of parsingResults.warnings) {
if (warning.level === DiagnosticLevel.Error) {
throw CompilerError.from(warning);
} else if (warning.level === DiagnosticLevel.Warning) {
/* eslint-disable-next-line no-console */
console.warn(warning.message);
} else {
/* eslint-disable-next-line no-console */
console.log(warning.message);
}
}
if (!parsingResults.root) {
throw generateCompilerError(TemplateErrors.INVALID_TEMPLATE);
}
const { code } = generate(parsingResults.root, state);
return new Function(TEMPLATE_MODULES_PARAMETER, code);
}
export function normalizeAttributeValue(
attr: parse5.AST.Default.Attribute,
raw: string,
tag: string
): {
value: string;
escapedExpression: boolean;
} {
const { name, value } = attr;
if (booleanAttributes.has(name)) {
if (value === 'true') {
throw generateCompilerError(ParserDiagnostics.BOOLEAN_ATTRIBUTE_TRUE, {
messageArgs: [tag, name, value],
});
} else if (value === 'false') {
throw generateCompilerError(ParserDiagnostics.BOOLEAN_ATTRIBUTE_FALSE, {
messageArgs: [tag, name, value],
});
}
}
const isQuoted = isQuotedAttribute(raw);
const isEscaped = isEscapedAttribute(raw);
if (!isEscaped && isExpression(value)) {
if (isQuoted) {
// <input value="{myValue}">
// -> ambiguity if the attribute value is a template identifier or a string literal.
messageArgs: [tag, name, value],
});
}
}
const isQuoted = isQuotedAttribute(raw);
const isEscaped = isEscapedAttribute(raw);
if (!isEscaped && isExpression(value)) {
if (isQuoted) {
// <input value="{myValue}">
// -> ambiguity if the attribute value is a template identifier or a string literal.
const unquoted = raw.replace(/"/g, '');
const escaped = raw.replace('"{', '"\\{');
throw generateCompilerError(ParserDiagnostics.AMBIGUOUS_ATTRIBUTE_VALUE, {
messageArgs: [raw, unquoted, escaped],
});
}
// <input value="{myValue}">
// -> Valid identifier.
return { value, escapedExpression: false };
} else if (!isEscaped && isPotentialExpression(value)) {
const isExpressionEscaped = value.startsWith(`\\${EXPRESSION_SYMBOL_START}`);
const isExpressionNextToSelfClosing =
value.startsWith(EXPRESSION_SYMBOL_START) &&
value.endsWith(`${EXPRESSION_SYMBOL_END}/`) &&
!isQuoted;
if (isExpressionNextToSelfClosing) {
// <input value="{myValue}/">
diagnostics.push(
generateCompilerDiagnostic(ModuleResolutionErrors.RELATIVE_DYNAMIC_IMPORT)
);
}
const result = output[0];
code = result.code;
map = result.map;
} catch (e) {
// Rollup may have clobbered error.code with its own data
if (e instanceof CompilerError && (e as any).pluginCode) {
e.code = (e as any).pluginCode;
}
const diagnostic = normalizeToDiagnostic(ModuleResolutionErrors.MODULE_RESOLUTION_ERROR, e);
diagnostic.level = DiagnosticLevel.Fatal;
diagnostics.push(diagnostic);
}
return {
diagnostics,
code,
map,
};
}
plugins,
onwarn: handleRollupWarning(diagnostics),
});
const { output } = await rollupBundler.generate({
amd: { id: namespace + '/' + name },
strict: false,
sourcemap: outputConfig.sourcemap,
format,
});
// Rollup produces multiple chunks when a module uses "import()" with a relative import
// path. We need to ensure the compiled module only contains the main chunk.
if (output.length > 1) {
diagnostics.push(
generateCompilerDiagnostic(ModuleResolutionErrors.RELATIVE_DYNAMIC_IMPORT)
);
}
const result = output[0];
code = result.code;
map = result.map;
} catch (e) {
// Rollup may have clobbered error.code with its own data
if (e instanceof CompilerError && (e as any).pluginCode) {
e.code = (e as any).pluginCode;
}
const diagnostic = normalizeToDiagnostic(ModuleResolutionErrors.MODULE_RESOLUTION_ERROR, e);
diagnostic.level = DiagnosticLevel.Fatal;
diagnostics.push(diagnostic);
}
export default function templateTransform(
src: string,
filename: string,
options: NormalizedCompilerOptions
): FileTransformerResult {
let result;
try {
result = compile(src, {
experimentalDynamicDirective: !!options.experimentalDynamicComponent,
});
} catch (e) {
throw normalizeToCompilerError(TransformerErrors.HTML_TRANSFORMER_ERROR, e, { filename });
}
const fatalError = result.warnings.find(warning => warning.level === DiagnosticLevel.Error);
if (fatalError) {
throw CompilerError.from(fatalError, { filename });
}
// Rollup only cares about the mappings property on the map. Since producing a source map for
// the template doesn't make sense, the transform returns an empty mappings.
return {
code: serialize(result.code, filename, options),
map: { mappings: '' },
};
}
allowDefinition: customProperties.allowDefinition,
resolverModule:
customProperties.resolution.type === 'module'
? customProperties.resolution.name
: undefined,
},
outputConfig: {
minify,
},
};
let res;
try {
res = styleCompiler.transform(src, filename, styleCompilerConfig);
} catch (e) {
throw normalizeToCompilerError(TransformerErrors.CSS_TRANSFORMER_ERROR, e, { filename });
}
// Rollup only cares about the mappings property on the map. Since producing a source map for
// the styles doesn't make sense, the transform returns an empty mappings.
return {
code: res.code,
map: { mappings: '' },
};
}
export default function parseInlineStyles(
src: string,
stylesheetConfig: StylesheetConfig
): Statement[] {
let result;
try {
result = styleCompiler.transform(src, 'template_inline_styles', stylesheetConfig);
} catch (e) {
throw normalizeToCompilerError(TransformerErrors.CSS_IN_HTML_ERROR, e);
}
// The style compiler produces a module string
const { code } = result;
// Convert it to an AST
const parsed = babylon.parse(code, { sourceType: 'module' });
// Return the body of the module
return parsed.program.body;
}