Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
285 changes: 227 additions & 58 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"eslint": "^9.39.2",
"globals": "^17.3.0",
"prettier": "^3.8.1",
"typescript": "^5.9.3",
"typescript": "^6.0.0",
"vitepress": "^1.6.4",
"vitest": "^4.1.4"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/owl/src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function parseXML(xml: string): XMLDocument {
const doc = parser.parseFromString(xml, "text/xml");
if (doc.getElementsByTagName("parsererror").length) {
let msg = "Invalid XML in template.";
const parsererrorText = doc.getElementsByTagName("parsererror")[0].textContent;
const parsererrorText = doc.getElementsByTagName("parsererror")[0]!.textContent;
if (parsererrorText) {
msg += "\nThe parser has produced the following error message:\n" + parsererrorText;
const re = /\d+/g;
Expand Down
65 changes: 33 additions & 32 deletions packages/owl/src/compiler/code_generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ export class CodeGenerator {
const bareArrowMatch = !arrowMatch && compiled.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=>/);

if (arrowMatch) {
const inner = arrowMatch[1].slice(1, -1).trim();
const inner = arrowMatch[1]!.slice(1, -1).trim();
const rest = compiled.slice(arrowMatch[0].length);
hoistedExpr = inner ? `(ctx,${inner})=>${rest}` : `(ctx)=>${rest}`;
} else if (bareArrowMatch) {
Expand Down Expand Up @@ -573,14 +573,14 @@ export class CodeGenerator {
for (let key in ast.attrs) {
let expr, attrName;
if (key.startsWith("t-attf")) {
expr = interpolate(ast.attrs[key]);
expr = interpolate(ast.attrs[key]!);
const idx = block!.insertData(expr, "attr");

attrName = key.slice(7);
attrs["block-attribute-" + idx] = attrName;
} else if (key.startsWith("t-att")) {
attrName = key === "t-att" ? null : key.slice(6);
expr = compileExpr(ast.attrs[key]);
expr = compileExpr(ast.attrs[key]!);
if (attrName && isProp(ast.tag, attrName)) {
if (attrName === "readonly") {
// the property has a different name than the attribute
Expand All @@ -605,11 +605,11 @@ export class CodeGenerator {
}
} else if (this.translatableAttributes.includes(key)) {
const attrTranslationCtx = ast.attrsTranslationCtx?.[key] || ctx.translationCtx;
attrs[key] = this.translateFn(ast.attrs[key], attrTranslationCtx);
attrs[key] = this.translateFn(ast.attrs[key]!, attrTranslationCtx);
} else {
expr = `"${ast.attrs[key]}"`;
expr = `"${ast.attrs[key]!}"`;
attrName = key;
attrs[key] = ast.attrs[key];
attrs[key] = ast.attrs[key]!;
}

if (attrName === "value" && ctx.tModelSelectedExpr) {
Expand Down Expand Up @@ -679,7 +679,7 @@ export class CodeGenerator {

// event handlers
for (let ev in ast.on) {
const name = this.generateHandlerCode(ev, ast.on[ev]);
const name = this.generateHandlerCode(ev, ast.on[ev]!);
const idx = block!.insertData(name, "hdlr");
attrs[`block-handler-${idx}`] = ev;
}
Expand Down Expand Up @@ -708,7 +708,7 @@ export class CodeGenerator {
block!.currentDom = dom;
const children = ast.content;
for (let i = 0; i < children.length; i++) {
const child = ast.content[i];
const child = ast.content[i]!;
const subCtx = createContext(ctx, {
block,
index: block!.childNumber,
Expand All @@ -729,11 +729,11 @@ export class CodeGenerator {
if (block!.children.length && block!.hasDynamicChildren) {
const code = this.target.code;
const children = block!.children.slice();
let current = children.shift();
let current = children.shift()!;
for (let i = codeIdx; i < code.length; i++) {
if (code[i].trimStart().startsWith(`const ${current!.varName} `)) {
code[i] = code[i].replace(`const ${current!.varName}`, current!.varName);
current = children.shift();
if (code[i]!.trimStart().startsWith(`const ${current.varName} `)) {
code[i] = code[i]!.replace(`const ${current.varName}`, current.varName);
current = children.shift()!;
if (!current) break;
}
}
Expand Down Expand Up @@ -817,11 +817,11 @@ export class CodeGenerator {
if (block!.children.length) {
const code = this.target.code;
const children = block!.children.slice();
let current = children.shift();
let current = children.shift()!;
for (let i = codeIdx; i < code.length; i++) {
if (code[i].trimStart().startsWith(`const ${current!.varName} `)) {
code[i] = code[i].replace(`const ${current!.varName}`, current!.varName);
current = children.shift();
if (code[i]!.trimStart().startsWith(`const ${current.varName} `)) {
code[i] = code[i]!.replace(`const ${current.varName}`, current.varName);
current = children.shift()!;
if (!current) break;
}
}
Expand Down Expand Up @@ -914,7 +914,7 @@ export class CodeGenerator {
// Check if there are non-DOM directives (like t-set) after the DOM child.
// If so, defer the return so those directives are compiled before it.
const shouldDefer =
!this.target.hasRoot && ast.content[ast.content.length - 1].hasNoRepresentation;
!this.target.hasRoot && ast.content[ast.content.length - 1]!.hasNoRepresentation;
if (shouldDefer) {
this.target.deferReturn = true;
}
Expand All @@ -932,7 +932,7 @@ export class CodeGenerator {
}
let index = 0;
for (let i = 0, l = ast.content.length; i < l; i++) {
const child = ast.content[i];
const child = ast.content[i]!;
const forceNewBlock = !child.hasNoRepresentation;
const subCtx = createContext(ctx, {
block,
Expand All @@ -948,11 +948,11 @@ export class CodeGenerator {
if (block!.hasDynamicChildren && block!.children.length) {
const code = this.target.code;
const children = block!.children.slice();
let current = children.shift();
let current = children.shift()!;
for (let i = codeIdx; i < code.length; i++) {
if (code[i].trimStart().startsWith(`const ${current!.varName} `)) {
code[i] = code[i].replace(`const ${current!.varName}`, current!.varName);
current = children.shift();
if (code[i]!.trimStart().startsWith(`const ${current.varName} `)) {
code[i] = code[i]!.replace(`const ${current.varName}`, current.varName);
current = children.shift()!;
if (!current) break;
}
}
Expand Down Expand Up @@ -1110,7 +1110,7 @@ export class CodeGenerator {
}
if (name.includes(".")) {
let [_name, suffix] = name.split(".");
name = _name;
name = _name!;
switch (suffix) {
case "bind":
value = `(${value}).bind(this)`;
Expand Down Expand Up @@ -1155,14 +1155,15 @@ export class CodeGenerator {

for (let p in ast.props || {}) {
let [name, suffix] = p.split(".");
name = name!;

if (suffix) {
// .alike, .bind, .translate — delegate to formatProp, no propList entry
props.push(this.formatProp(p, ast.props![p], ast.propsTranslationCtx, ctx.translationCtx));
props.push(this.formatProp(p, ast.props![p]!, ast.propsTranslationCtx, ctx.translationCtx));
continue;
}

const { expr: compiledValue, freeVariables } = processExpr(ast.props![p]);
const { expr: compiledValue, freeVariables } = processExpr(ast.props![p]!);

const propName = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
props.push(`${propName}: ${compiledValue || undefined}`);
Expand All @@ -1183,21 +1184,21 @@ export class CodeGenerator {
if (ast.slots) {
let slotStr: string[] = [];
for (let slotName in ast.slots) {
const slotAst = ast.slots[slotName];
const slotAst = ast.slots[slotName]!;
const params = [];
if (slotAst.content) {
const name = this.compileInNewTarget("slot", slotAst.content, ctx, slotAst.on);
params.push(`__render: ${name}.bind(this), __ctx: ctx`);
}
const scope = ast.slots[slotName].scope;
const scope = slotAst.scope;
if (scope) {
params.push(`__scope: "${scope}"`);
}
if (ast.slots[slotName].attrs) {
if (slotAst.attrs) {
params.push(
...this.formatPropObject(
ast.slots[slotName].attrs!,
ast.slots[slotName].attrsTranslationCtx,
slotAst.attrs!,
slotAst.attrsTranslationCtx,
ctx.translationCtx
)
);
Expand Down Expand Up @@ -1285,7 +1286,7 @@ export class CodeGenerator {
let handlerId = generateId("hdlr");
let idx = handlers.push(handlerId) - 1;
spec[ev] = idx;
const handler = this.generateHandlerCode(ev, on[ev]);
const handler = this.generateHandlerCode(ev, on[ev]!);
this.define(handlerId, handler);
}
this.staticDefs.push({ id: name, expr: `createCatcher(${JSON.stringify(spec)})` });
Expand All @@ -1309,7 +1310,7 @@ export class CodeGenerator {
this.slotNames.add(ast.name);
}
const attrs = { ...ast.attrs };
const dynProps = attrs["t-props"];
const dynProps = attrs["t-props"] ?? null;
delete attrs["t-props"];
let key = this.target.loopLevel ? `key${this.target.loopLevel}` : "key";
if (isMultiple) {
Expand Down
28 changes: 14 additions & 14 deletions packages/owl/src/compiler/inline_expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ let tokenizeNumber: Tokenizer = function (expr) {
let s = expr[0];
if (s && s.match(/[0-9]/)) {
let i = 1;
while (expr[i] && expr[i].match(/[0-9]|\./)) {
s += expr[i];
while (expr[i] && expr[i]!.match(/[0-9]|\./)) {
s += expr[i]!
i++;
}
return { type: "VALUE", value: s };
Expand All @@ -143,12 +143,12 @@ let tokenizeSymbol: Tokenizer = function (expr) {
let s = expr[0];
if (s && s.match(/[a-zA-Z_\$]/)) {
let i = 1;
while (expr[i] && expr[i].match(/[\w\$]/)) {
s += expr[i];
while (expr[i] && expr[i]!.match(/[\w\$]/)) {
s += expr[i]!
i++;
}
if (s in WORD_REPLACEMENT) {
return { type: "OPERATOR", value: WORD_REPLACEMENT[s], size: s.length };
return { type: "OPERATOR", value: WORD_REPLACEMENT[s]!, size: s.length };
}
return { type: "SYMBOL", value: s };
} else {
Expand All @@ -159,7 +159,7 @@ let tokenizeSymbol: Tokenizer = function (expr) {
const tokenizeStatic: Tokenizer = function (expr) {
const char = expr[0];
if (char && char in STATIC_TOKEN_MAP) {
return { type: STATIC_TOKEN_MAP[char], value: char };
return { type: STATIC_TOKEN_MAP[char]!, value: char };
}
return false;
};
Expand Down Expand Up @@ -277,7 +277,7 @@ export function processExpr(expr: string): ProcessedExpr {
let topLevelArrowIndex = -1;

while (i < tokens.length) {
let token = tokens[i];
let token = tokens[i]!;
let prevToken = tokens[i - 1];
let nextToken = tokens[i + 1];
let groupType = stack[stack.length - 1];
Expand All @@ -301,10 +301,10 @@ export function processExpr(expr: string): ProcessedExpr {
if (
groupType === "LEFT_BRACE" &&
isLeftSeparator(prevToken) &&
isRightSeparator(nextToken)
nextToken && isRightSeparator(nextToken)
) {
tokens.splice(i + 1, 0, { type: "COLON", value: ":" }, { ...token });
nextToken = tokens[i + 1];
nextToken = tokens[i + 1]!;
}

if (prevToken.type === "OPERATOR" && prevToken.value === ".") {
Expand All @@ -325,10 +325,10 @@ export function processExpr(expr: string): ProcessedExpr {
}
if (token.type === "RIGHT_PAREN") {
let j = i - 1;
while (j > 0 && tokens[j].type !== "LEFT_PAREN") {
if (tokens[j].type === "SYMBOL" && tokens[j].originalValue) {
tokens[j].value = tokens[j].originalValue!;
localVars.add(tokens[j].value);
while (j > 0 && tokens[j]!.type !== "LEFT_PAREN") {
if (tokens[j]!.type === "SYMBOL" && tokens[j]!.originalValue) {
tokens[j]!.value = tokens[j]!.originalValue!;
localVars.add(tokens[j]!.value);
}
j--;
}
Expand Down Expand Up @@ -363,7 +363,7 @@ export function processExpr(expr: string): ProcessedExpr {
freeVariables = [];
const seen = new Set<string>();
for (let i = topLevelArrowIndex + 1; i < tokens.length; i++) {
const t = tokens[i];
const t = tokens[i]!;
if (t.varName && !t.isLocal && t.varName !== "this" && !seen.has(t.varName)) {
seen.add(t.varName);
freeVariables.push(t.varName);
Expand Down
14 changes: 7 additions & 7 deletions packages/owl/src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ function parseTCustom(node: Element, ctx: ParsingContext): AST | null {
throw new OwlError("Missing custom directive name with t-custom directive");
}
if (attr.startsWith("t-custom-")) {
const directiveName = attr.split(".")[0].slice(9);
const directiveName = attr.split(".")[0]!.slice(9);
const customDirective = ctx.customDirectives[directiveName];
if (!customDirective) {
throw new OwlError(`Custom directive "${directiveName}" is not defined`);
Expand Down Expand Up @@ -704,7 +704,7 @@ function parseComponent(node: Element, ctx: ParsingContext): AST | null {
);
}

if (!(firstLetter === firstLetter.toUpperCase() || isDynamic)) {
if (!(firstLetter === firstLetter!.toUpperCase() || isDynamic)) {
return null;
}
if (isDynamic) {
Expand Down Expand Up @@ -760,7 +760,7 @@ function parseComponent(node: Element, ctx: ParsingContext): AST | null {
let el = slotNode.parentElement!;
let isInSubComponent = false;
while (el && el !== clone) {
if (el!.hasAttribute("t-component") || el!.tagName[0] === el!.tagName[0].toUpperCase()) {
if (el!.hasAttribute("t-component") || el!.tagName[0] === el!.tagName[0]!.toUpperCase()) {
isInSubComponent = true;
break;
}
Expand Down Expand Up @@ -960,7 +960,7 @@ function parseChildNodes(node: Element, ctx: ParsingContext): AST | null {
case 0:
return null;
case 1:
return children[0];
return children[0]!;
default:
return makeASTMulti(children);
}
Expand All @@ -977,10 +977,10 @@ function parseChildNodes(node: Element, ctx: ParsingContext): AST | null {
function normalizeTIf(el: Element) {
let tbranch = el.querySelectorAll("[t-elif], [t-else]");
for (let i = 0, ilen = tbranch.length; i < ilen; i++) {
let node = tbranch[i];
let node = tbranch[i]!;
let prevElem = node.previousElementSibling!;
let pattr = (name: string) => prevElem.getAttribute(name);
let nattr = (name: string) => +!!node.getAttribute(name);
let nattr = (name: string) => +!!node!.getAttribute(name);
if (prevElem && (pattr("t-if") || pattr("t-elif"))) {
if (pattr("t-foreach")) {
throw new OwlError(
Expand Down Expand Up @@ -1021,7 +1021,7 @@ function normalizeTIf(el: Element) {
*/
function normalizeTOut(el: Element) {
const elements = [...el.querySelectorAll(`[t-out]`)].filter(
(el) => el.tagName[0] === el.tagName[0].toUpperCase() || el.hasAttribute("t-component")
(el) => el.tagName[0] === el.tagName[0]!.toUpperCase() || el.hasAttribute("t-component")
);
for (const el of elements) {
if (el.childNodes.length) {
Expand Down
2 changes: 1 addition & 1 deletion packages/owl/src/compiler/standalone/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export async function compileTemplates(paths: string[]) {
const fileContent = xmlStrings[i];
process.stdout.write(`.`);
const parser = new DOMParser();
const doc = parser.parseFromString(fileContent, "text/xml");
const doc = parser.parseFromString(fileContent!, "text/xml");
for (const template of doc.querySelectorAll("[t-name]")) {
const name = template.getAttribute("t-name");
if (template.hasAttribute("owl")) {
Expand Down
4 changes: 2 additions & 2 deletions packages/owl/src/runtime/blockdom/attributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ function toClassObj(expr: string | number | { [c: string]: any }) {
}
let words = split.call(str, wordRegexp);
for (let i = 0, l = words.length; i < l; i++) {
result[words[i]] = true;
result[words[i]!] = true;
}
return result;
case "object":
Expand Down Expand Up @@ -159,7 +159,7 @@ const CSS_PROP_CACHE: { [key: string]: string } = {};

function toKebabCase(prop: string): string {
if (prop in CSS_PROP_CACHE) {
return CSS_PROP_CACHE[prop];
return CSS_PROP_CACHE[prop]!;
}
const result = prop.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
CSS_PROP_CACHE[prop] = result;
Expand Down
Loading
Loading