Skip to content

Commit

Permalink
Version 1.1.0 (#31)
Browse files Browse the repository at this point in the history
* Support for logic expressions in strategies
* Added tests for new combination logic
* Added ability to specify a custom event strategy
  • Loading branch information
Accudio authored Aug 25, 2023
1 parent a406e3c commit d66fcc1
Show file tree
Hide file tree
Showing 18 changed files with 604 additions and 160 deletions.
167 changes: 126 additions & 41 deletions dist/async-alpine.cjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,36 @@ __export(exports, {
default: () => AsyncAlpine
});

// src/core/strategies/index.js
var strategies_exports = {};
__export(strategies_exports, {
eager: () => eager_default,
event: () => event_default,
idle: () => idle_default,
media: () => media_default,
visible: () => visible_default
});

// src/core/strategies/eager.js
var eager = () => {
return true;
};
var eager_default = eager;

// src/core/strategies/event.js
var event = (component) => {
var event = ({ component, argument }) => {
return new Promise((resolve) => {
window.addEventListener("async-alpine:load", (e) => {
if (e.detail.id !== component.id)
return;
resolve();
});
if (argument) {
window.addEventListener(argument, () => resolve(), { once: true });
} else {
const cb = (e) => {
if (e.detail.id !== component.id)
return;
window.removeEventListener("async-alpine:load", cb);
resolve();
};
window.addEventListener("async-alpine:load", cb);
}
});
};
var event_default = event;
Expand All @@ -36,11 +58,13 @@ var idle = () => {
var idle_default = idle;

// src/core/strategies/media.js
var media = (requirement) => {
var media = ({ argument }) => {
return new Promise((resolve) => {
const queryStart = requirement.indexOf("(");
const query = requirement.slice(queryStart);
const mediaQuery = window.matchMedia(query);
if (!argument) {
console.log("Async Alpine: media strategy requires a media query. Treating as 'eager'");
return resolve();
}
const mediaQuery = window.matchMedia(`(${argument})`);
if (mediaQuery.matches) {
resolve();
} else {
Expand All @@ -51,13 +75,9 @@ var media = (requirement) => {
var media_default = media;

// src/core/strategies/visible.js
var visible = (component, requirement) => {
var visible = ({ component, argument }) => {
return new Promise((resolve) => {
let rootMargin = "0px 0px 0px 0px";
if (requirement.indexOf("(") !== -1) {
const rootMarginStart = requirement.indexOf("(") + 1;
rootMargin = requirement.slice(rootMarginStart, -1);
}
const rootMargin = argument || "0px 0px 0px 0px";
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
observer.disconnect();
Expand All @@ -69,6 +89,79 @@ var visible = (component, requirement) => {
};
var visible_default = visible;

// src/core/requirement-parser.js
function parseRequirements(expression) {
const tokens = tokenize(expression);
let ast = parseExpression(tokens);
if (ast.type === "method") {
return {
type: "expression",
operator: "&&",
parameters: [ast]
};
}
return ast;
}
function tokenize(expression) {
const regex = /\s*([()])\s*|\s*(\|\||&&|\|)\s*|\s*((?:[^()&|]+\([^()]+\))|[^()&|]+)\s*/g;
const tokens = [];
let match;
while ((match = regex.exec(expression)) !== null) {
const [, parenthesis, operator, token] = match;
if (parenthesis !== void 0) {
tokens.push({ type: "parenthesis", value: parenthesis });
} else if (operator !== void 0) {
tokens.push({
type: "operator",
value: operator === "|" ? "&&" : operator
});
} else {
const tokenObj = {
type: "method",
method: token.trim()
};
if (token.includes("(")) {
tokenObj.method = token.substring(0, token.indexOf("(")).trim();
tokenObj.argument = token.substring(token.indexOf("(") + 1, token.indexOf(")"));
}
if (token.method === "immediate") {
token.method = "eager";
}
tokens.push(tokenObj);
}
}
return tokens;
}
function parseExpression(tokens) {
let ast = parseTerm(tokens);
while (tokens.length > 0 && (tokens[0].value === "&&" || tokens[0].value === "|" || tokens[0].value === "||")) {
const operator = tokens.shift().value;
const right = parseTerm(tokens);
if (ast.type === "expression" && ast.operator === operator) {
ast.parameters.push(right);
} else {
ast = {
type: "expression",
operator,
parameters: [ast, right]
};
}
}
return ast;
}
function parseTerm(tokens) {
if (tokens[0].value === "(") {
tokens.shift();
const ast = parseExpression(tokens);
if (tokens[0].value === ")") {
tokens.shift();
}
return ast;
} else {
return tokens.shift();
}
}

// src/core/async-alpine.js
var internalNamePrefix = "__internal_";
var AsyncAlpine = {
Expand All @@ -78,7 +171,7 @@ var AsyncAlpine = {
alpinePrefix: "x-",
root: "load",
inline: "load-src",
defaultStrategy: "immediate"
defaultStrategy: "eager"
},
_alias: false,
_data: {},
Expand Down Expand Up @@ -154,33 +247,25 @@ var AsyncAlpine = {
});
},
async _componentStrategy(component) {
const requirements = component.strategy.split("|").map((requirement) => requirement.trim()).filter((requirement) => requirement !== "immediate").filter((requirement) => requirement !== "eager");
if (!requirements.length) {
await this._download(component.name);
this._activate(component);
return;
}
let promises = [];
for (let requirement of requirements) {
if (requirement === "idle") {
promises.push(idle_default());
continue;
}
if (requirement.startsWith("visible")) {
promises.push(visible_default(component, requirement));
continue;
}
if (requirement.startsWith("media")) {
promises.push(media_default(requirement));
continue;
const requirements = parseRequirements(component.strategy);
await this._generateRequirements(component, requirements);
await this._download(component.name);
this._activate(component);
},
_generateRequirements(component, obj) {
if (obj.type === "expression") {
if (obj.operator === "&&") {
return Promise.all(obj.parameters.map((param) => this._generateRequirements(component, param)));
}
if (requirement === "event") {
promises.push(event_default(component));
if (obj.operator === "||") {
return Promise.any(obj.parameters.map((param) => this._generateRequirements(component, param)));
}
}
Promise.all(promises).then(async () => {
await this._download(component.name);
this._activate(component);
if (!strategies_exports[obj.method])
return false;
return strategies_exports[obj.method]({
component,
argument: obj.argument
});
},
async _download(name) {
Expand Down
Loading

0 comments on commit d66fcc1

Please sign in to comment.