diff --git a/docs/architecture.md b/docs/architecture.md index a18812f0..e7909705 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -66,3 +66,4 @@ Utility scripts. - `export-results.ts` - Fetch all Firestore responses and generate results.json - `generate-questions.ts` - Parse YAML files and create questions.json +- `query-results.ts` - CLI to query and filter survey results (see [docs/query-results.md](./query-results.md)) diff --git a/docs/query-results.md b/docs/query-results.md new file mode 100644 index 00000000..3fecb6b9 --- /dev/null +++ b/docs/query-results.md @@ -0,0 +1,51 @@ +# `query-results` CLI + +Query survey results from the command line without running the dev server. + +```bash +pnpm query-results [--year=YYYY] [--format=text|json] [--filter=question=choice] +``` + +## Arguments + +- `` — question ID (e.g. `profile-q-0`) or case-insensitive label substring (e.g. `gender`). Must resolve to exactly one question. +- `--year=YYYY` — target year (default: latest available) +- `--format=text|json` — output format (default: `json`) +- `--filter=question=choice` — repeatable; AND logic. `question` resolves same as main arg. `choice` is either a numeric index or a case-insensitive label substring. + +## Examples + +```bash +# Basic query +pnpm query-results "gender" +pnpm query-results "profile-q-0" --format=text + +# Filter by single condition +pnpm query-results "tech-q-3" --filter="gender=Female" +pnpm query-results "tech-q-3" --filter="profile-q-0=1" # choice by index + +# Filter by multiple conditions (AND) +pnpm query-results "work-q-4" --filter="gender=Female" --filter="profile-q-1=2" + +# Text format with filter +pnpm query-results "gender" --format=text --filter="profile-q-1=25 to 34" +``` + +## JSON output + +```json +{ + "id": "tech-q-3", + "question": "What are the front-end frameworks/libraries you are using on a daily basis?", + "multiple": true, + "total": 84, + "skipped": 35, + "choices": [ + { "label": "React.js", "count": 28, "percentage": 33.3 } + ], + "filters": [{ "question": "What is your gender?", "choice": "Female" }], + "year": 2025 +} +``` + +`filters` is only present when `--filter` args are used. diff --git a/package.json b/package.json index 8eeff274..08156932 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "generate-questions": " tsx ./scripts/generate-questions.ts", "generate-questions:ci": " tsx ./scripts/generate-questions.ts", "export-results": " tsx --env-file=.env.local ./scripts/export-results.ts", - "export-results:ci": " tsx ./scripts/export-results.ts" + "export-results:ci": " tsx ./scripts/export-results.ts", + "query-results": "tsx ./scripts/query-results.ts" }, "dependencies": { "@astro-community/astro-embed-youtube": "^0.5.3", diff --git a/results/2025/sections/ai.mdx b/results/2025/sections/ai.mdx new file mode 100644 index 00000000..c44512e5 --- /dev/null +++ b/results/2025/sections/ai.mdx @@ -0,0 +1,90 @@ +--- +title: AI +position: 6 +--- + +# AI + +AI adoption among Moroccan developers has reached a tipping point. Daily usage has surged to 78.3%, nearly 4 in 5 respondents — up sharply from previous years. Beyond tools, developers are actively building with AI, and companies are beginning to put it into production. + +## Usage and Learning + +The vast majority of respondents now use AI tools daily (78.3%), with only 0.5% never having tried them at all. + + + + + + + + + + + + + +Around 80% of respondents are actively engaging with AI for development: 33.8% have started learning the basics, 27.4% can already build simple apps with third-party APIs, and 14.1% can build complex applications. + + + + + + + + + + + + + +ChatGPT remains the most-used AI tool at 81.6%, but Claude (59.9%) and Gemini (60.5%) have both climbed to second place territory. Cursor (22.1%) and GitHub Copilot (25.4%) lead among coding-specific tools. + + + +On the frameworks and models side, the OpenAI API leads at 47.5%, followed by Google Gemini API (32%) and Anthropic Claude API (27%). DeepSeek shows strong early adoption at 11.3%, and Llama (Meta) reaches 10.2%. + + + +Companies are increasingly moving AI from experimentation to production: 26.6% report having several use cases in production, and 15.7% have at least some. Still, 28.3% have not yet started adopting AI. + + + + + + + + + + + + + +## Productivity and Future of AI + +79.2% of respondents report meaningful productivity gains from AI tools (10%+), with nearly 30% saying they are now very productive (30–50% improvement) and 10.7% claiming 10x gains. + + + + + + + + + + + + + +On the question of AI replacing developers, 32% believe AI will displace 30–50% of developers, and 25% think 10–30%. Only 3.2% believe AI will completely replace developers, while 23.4% think the impact will be minimal. + + + + + + + + + + + + diff --git a/results/2025/sections/community.mdx b/results/2025/sections/community.mdx new file mode 100644 index 00000000..1a3aea16 --- /dev/null +++ b/results/2025/sections/community.mdx @@ -0,0 +1,50 @@ +--- +title: Community +position: 7 +--- + +# Community + +The Moroccan tech community is growing, but participation gaps remain. This year we asked developers what holds them back, what they need, and how the community has shaped their careers. + +## Barriers to participation + +Time and discoverability are the two biggest obstacles: 46.4% cite work commitments, and 44.7% simply don't know where to find communities or events. Geographic distance (26.4%) and financial constraints (17.8%) also play a role. + + + +## What would make you attend more events + +More events closer to home tops the list (60.2%), followed by better timing like evenings and weekends (53.6%) and better networking opportunities (51.9%). Better speakers and hands-on workshops are also important factors. + + + +## Impact on career + +54.3% of respondents say the community hasn't had a direct impact on their career yet — a signal that there's still room to connect engagement with real outcomes. Among those who benefited, 24.4% learned career-advancing skills, 18.5% built their professional network, and 18.2% discovered new opportunities. + + + +## What developers need most + +Networking (58%), job opportunities and career guidance (57.2%), and mentorship from experienced developers (51.4%) are the top three needs. Collaboration on projects (47%) and access to advanced technical content (37.4%) also rank highly. + + + +## Most valuable content types + +Architecture and system design discussions top the list at 50.9%, closely followed by technical workshops (50%) and career development sessions covering interviews, negotiations, and CVs (48.4%). Case studies from Moroccan companies (46.3%) and freelancing/entrepreneurship guidance (41.7%) also show strong demand. + + + +## Open source contribution + +Only 10.7% of respondents already contribute to open source. The main barriers are not knowing how to get started (44.1%), not knowing how to find projects (34.4%), lack of time (33.8%), and self-doubt about code quality (32.1%). + + + +## Primary social network + +LinkedIn dominates as the primary professional network for Moroccan developers at 55.3%. X (Twitter) is second at 14.6%, followed by YouTube (12.9%), Reddit (6.3%), and Discord (5.7%). + + diff --git a/results/2025/sections/education.mdx b/results/2025/sections/education.mdx new file mode 100644 index 00000000..ad49438a --- /dev/null +++ b/results/2025/sections/education.mdx @@ -0,0 +1,38 @@ +--- +title: Learning & Education +position: 3 +--- + +# Education and Learning + +Learning is a continuous process for software developers, who must constantly keep up with new technologies, paradigms, and tools. We asked respondents about what formal education missed, how they learn, and what challenges they face. + +## Gaps in formal education + +Only 17.5% of respondents feel their formal education prepared them well across the board. The top gaps identified are modern tech stacks (44.7%), development practices like version control and testing (42.5%), and real-world project experience (40.7%). + + + +## Read/Written languages + +Arabic and English remain virtually universal among respondents (98.4% and 97.7% respectively), closely followed by French at 87.4%. + + + +## Darija content + +Around 80% of respondents would benefit from some form of Darija content, with podcasts/audio (51.2%), tutorial videos (47%), and community discussions (45.8%) being the most requested formats. + + + +## Preferred learning platforms + +YouTube remains the dominant learning resource at 81.5%, but AI Assistants (ChatGPT, etc.) have surged to second place at 68.2%, ahead of official documentation (56.7%) and blog posts (39.4%). + + + +## Learning challenges + +Lack of time is the biggest obstacle to learning new technologies, cited by 61.9% of respondents. Keeping up with rapid changes (41%) and information overload (39.7%) follow closely, while only 7.4% cite language barriers as a challenge. + + diff --git a/results/2025/sections/overview.mdx b/results/2025/sections/overview.mdx new file mode 100644 index 00000000..5d161073 --- /dev/null +++ b/results/2025/sections/overview.mdx @@ -0,0 +1,38 @@ +--- +title: Overview +position: 1 +--- + +# Overview + +The sixth annual survey on Software Developers in Morocco brings together 1,007 responses from developers across Morocco and abroad. This year, we went beyond the usual "what" to ask more "why" — adding new questions on community barriers, education gaps, learning challenges, open source, and entrepreneurship to make the results more actionable for the community. + +Here are the most striking findings: + +- **AI has crossed a tipping point.** 78.3% of respondents use AI tools daily — up sharply year over year. Even more telling: AI assistants (91.1%) have overtaken Google (77.7%) as the go-to when stuck on a problem, for the first time in survey history. + +- **The community gap is real.** 54.3% say the tech community has had no direct impact on their career. Time and discoverability are the top barriers to participation. Only 10.7% contribute to open source, and most don't know where to start. + +- **Emigration pressure remains high.** Nearly 40% of respondents plan to work outside Morocco within the next 24 months — and among those already abroad, most are not planning to return soon. + +- **Formal education is falling short.** Only 17.5% feel their education prepared them well. The biggest gaps: modern tech stacks, development practices like version control and testing, and real-world project experience. + +- **Entrepreneurship is rising.** 32% of respondents are already building a side project or planning to start a business in the next year — a signal of growing ambition beyond employment. + +- **Remote work preference vs. reality.** Over 92% prefer hybrid or full remote, yet back-to-office arrangements have grown to 26% — a widening gap between what developers want and what employers offer. + +
+Dive into the sections below to explore the full data, and share the results with your network. + +## A word about methodology + +At our core, we value anonymity and as such, all collected data from the survey is anonymized. Raw results and the website code are also available under the BY-NC-SA 2.0 license on the [GeeksBlaBla GitHub organization](https://github.com/geeksblabla/stateofdev.ma). + +Please note that not all fields in the survey were mandatory, which may result in some results and graphics not reflecting the total number of respondents for every question. + +We extend our heartfelt thanks to all our contributors and those who helped share the survey, and we eagerly await your feedback and for you to share the results with your network. + +Finally, we express our gratitude to all participants who took the time to complete the survey. Your input is invaluable and we hope you find the results as interesting as we do. + +
+
diff --git a/results/2025/sections/profile.mdx b/results/2025/sections/profile.mdx new file mode 100644 index 00000000..e22712b1 --- /dev/null +++ b/results/2025/sections/profile.mdx @@ -0,0 +1,103 @@ +--- +title: Profile +position: 2 +--- + +# Profile + +The objective of this first section is to get insights into the profile and the skills of the people working in Software Engineering in Morocco and abroad. The vast majority of respondents (88%) are men. Most are young developers aged 18 to 34 (93%), primarily based in Casablanca-Settat and Rabat-Salé-Kénitra, with a growing share working or planning to work abroad. + +## Gender + +Although the presence of women in the IT sector is slowly increasing, the field remains highly dominated by men — 88.2% male and 11.8% female among the 1,007 respondents who answered this question. + + + +## Age + +Over 93% of respondents are aged between 18 and 34 years old, indicating a predominantly junior to mid-level talent pool with a strong demand for entry-level and intermediate positions. + + + +## Location + +Casablanca-Settat leads with 37.1% of respondents, followed by Rabat-Salé-Kénitra at 17.5%. Europe-based respondents account for 8.4%, reflecting a notable diaspora presence. + + + +## Roles + +Full-stack development dominates at 40.1%, making it by far the most common role. Students coding professionally represent 14.3%, and back-end developers come in third at 10.1%. AI engineering emerges as a distinct category at 3.2%. + + + +## Highest degree + +Nearly half of respondents (47.9%) hold a Bac+5 (Master's equivalent). Coding schools such as 1337, YouCode, and Solicode represent 16.6% of education backgrounds, reflecting their growing footprint in the ecosystem. + + + +## Years coding professionally + +The majority of participants have limited professional coding experience: 15% have none, 19.1% have less than a year, and 26.7% have 1–2 years. Together, these three groups make up over 60% of respondents. + + + +## Coding as a hobby + +87.2% of respondents code outside of work or studies. The most common motivations are fun or learning (59%), portfolio/career building (36.5%), and freelance or product work (27%). + + + +## Plans to work abroad + +Close to 40% of respondents plan to work outside Morocco within the next 24 months (13.9% within 12 months, 24.6% within 24 months). 30.8% are still hesitating, and only 19.6% have no plans at all. + + + + v["profile-q-7"] !== 3} + title={false} + showEmptyOptions={false} + /> + + + v["profile-q-7"] !== 3} + title={false} + showEmptyOptions={false} + /> + + + v["profile-q-7"] !== 3} + title={false} + showEmptyOptions={false} + /> + + + v["profile-q-7"] !== 3} + title={false} + showEmptyOptions={false} + /> + + + +## Plans to come back to Morocco + +Among the 112 respondents currently working outside Morocco, most are not planning a return soon: 26.2% plan to stay abroad, 40.2% would return but not in the near future, and 22.4% are still hesitating. + + v["profile-q-7"] === 3} + title={false} +/> diff --git a/results/2025/sections/tech.mdx b/results/2025/sections/tech.mdx new file mode 100644 index 00000000..302587a5 --- /dev/null +++ b/results/2025/sections/tech.mdx @@ -0,0 +1,185 @@ +--- +title: Technology +position: 5 +--- + +# Technology + +Python and JavaScript top the list of most-loved languages this year, while Go and Rust continue to dominate the "wanted" list — reflecting a growing appetite for performance-oriented and systems languages. + + + + + + + + + + + + + +## Front-end frameworks/libraries + +React.js remains the dominant front-end library in daily use at 46.3%, followed by Next.js (20.6%) and Angular (17.7%). On the wanted side, React.js and Next.js are nearly tied at the top, with Angular and Vue.js also drawing interest. + + + + + + + + + + +## CSS frameworks + +Tailwind CSS has cemented its lead at 48.4%, ahead of CSS Frameworks like Bootstrap and Material UI (35.1%) and plain CSS (32.8%). Shadcn UI also shows strong adoption at 18.4%. + + + + + + + + + + + + + +## Backend frameworks/libraries + +The Spring ecosystem leads backend adoption at 27.1%, followed by Express.js (16%), Laravel (11.3%), and FastAPI (10.8%). On the wanted side, Spring, Django, and Nest.js rank highest. + + + + + + + + + + +## Platforms and tools + +Docker is now the most widely used platform at 53.5%, surpassing Node.js (44.1%). The JVM follows at 25.3% and Kubernetes at 16%. On the wanted side, Kubernetes tops the list at 39.1%, well ahead of Docker (20.7%) and Terraform (15.1%). + + + + + + + + + + +## Primary operating systems + +Windows remains the most common OS at 36.9%, followed by Linux-based systems (25.9%), macOS (20.9%), and Windows + WSL2 (16.3%). + + + + + + + + + + + + + + + + + + + +## IDE & Code Editors + +VS Code dominates at 78.3%, with JetBrains IDEs second at 33.5%. Cursor has made a notable entry at 16%, reflecting the growing interest in AI-first editors. Vim/Neovim users account for around 12.8% combined. + + + +## How do you solve problems? + +AI assistants have become the primary go-to when stuck, used by 91.1% of respondents — overtaking Google (77.7%) for the first time. Official documentation (37.2%) and StackOverflow (30.2%) remain relevant but secondary. + + + + + + + + + + + + + +## Deployment environment + +Public cloud providers continue to dominate at 40.4%, while on-premise deployments account for 19.1%. Hybrid cloud and managed PaaS solutions each account for less than 10%. + + + + + + + + + + + + + + + + +## Cloud Providers + +AWS leads cloud platform usage at 25.2%, followed by Azure (15.1%) and GCP (10.1%). Vercel (8%) and Cloudflare (5.7%) show growing adoption among developers. Moroccan cloud providers remain marginally used at 1.5%. + + + + + + + + + + + + + + + + +## Database + +PostgreSQL has become the leading production database at 43.4%, ahead of MySQL/MariaDB (26.1%) and MongoDB (16.3%). SQL Server and Oracle each sit around 15%. SQL databases clearly dominate, though NoSQL options remain relevant. + + + + + + + + + + + + + + + + + + + +## Writing tests + +53% of respondents write unit tests, making it the most common form of quality assurance. Integration (28.5%) and end-to-end (18.7%) testing follow. However, 34.4% still don't write tests at all. + + diff --git a/results/2025/sections/work.mdx b/results/2025/sections/work.mdx new file mode 100644 index 00000000..bb64872d --- /dev/null +++ b/results/2025/sections/work.mdx @@ -0,0 +1,143 @@ +--- +title: Work +position: 4 +--- + +# Work + +The Moroccan tech job market continues to show resilience. Most respondents are employed, and the vast majority find work quickly after graduation. Remote and hybrid work arrangements remain highly valued, even as some companies push for a return to the office. + +## Employment status + +Full-time employees make up 58.5% of respondents, while students represent 17.1%. Freelancers account for 8.3%, and those looking for work represent 7.1%. + + + + + + + + + + + + + + + + + + + +## Working overtime + +About 18.4% of respondents never work overtime. However, the majority work beyond normal hours at varying frequencies, with nearly 34% doing so at least weekly. + + + +## Job satisfaction + +Over 52% of respondents report being satisfied (slightly or very) with their job, while 26.3% are neutral and about 21% are unsatisfied to some degree. + + + + + + + + + + + + + + + + + + + +## Unemployment after graduation + +60.9% of respondents found work immediately after graduation, and another 16.7% within 3 months — confirming that demand for developers in Morocco remains strong. + + + +## Choosing a job offer + +Salary tops the list at 84%, followed by company culture (61.4%) and remote work options (60.8%). Flexible schedules (56.7%) and professional development opportunities (55.7%) also rank highly. + + + + + + + + + + + + + + + + +## Preferred company size + +Larger companies (100+ employees) are preferred by 36.9% of respondents, followed by mid-sized companies of 31-100 employees (23.1%). Companies of 11-30 employees appeal to 19.7%. + + + +## Agile software development methodology + +Scrum remains the dominant methodology at 61.9%, while 22.5% of respondents report using no methodology at all. + + + +## Remote work + +Hybrid is the most common arrangement currently offered by employers (53.2%), while back-to-office has grown to 26%. Full remote stands at 20.8%. + + + + + + + + + + + + + + + + +Regardless of what employers offer, over 92% of respondents prefer some form of remote work — hybrid (61.6%) or full remote (30.6%). + + + + + + + + + + + + + + + + +## Sectors + +Fintech and e-banking lead as the top sector (16.5%), followed by e-commerce and retail (10.6%). Government/public sector (5.7%) and telecommunications (5.6%) also have notable representation. + + + +## Entrepreneurship + +Over a third of respondents (32%) are either already building a side project or planning to start a business within the next year. Another 22.1% are interested but not ready yet. Only about 10% have no interest in entrepreneurship. + + diff --git a/scripts/query-results.ts b/scripts/query-results.ts new file mode 100644 index 00000000..9a2d1e19 --- /dev/null +++ b/scripts/query-results.ts @@ -0,0 +1,220 @@ +import fs from "node:fs"; +import path from "node:path"; +import process from "node:process"; + +type ResultEntry = Results["results"][number]; + +function getLatestYear(resultsDir: string): string { + const entries = fs + .readdirSync(resultsDir) + .filter(e => /^\d{4}$/.test(e)) + .sort() + .reverse(); + if (entries.length === 0) + throw new Error("No year folders found in /results/"); + return entries[0]; +} + +function loadData(year: string) { + const base = path.resolve(process.cwd(), "results", year, "data"); + const qPath = path.join(base, "questions.json"); + const rPath = path.join(base, "results.json"); + + if (!fs.existsSync(qPath)) + throw new Error(`questions.json not found for year ${year}`); + if (!fs.existsSync(rPath)) + throw new Error(`results.json not found for year ${year}`); + + const questions = JSON.parse(fs.readFileSync(qPath, "utf-8")) as QuestionMap; + const { results } = JSON.parse(fs.readFileSync(rPath, "utf-8")) as { results: ResultEntry[] }; + return { questions, results }; +} + +function resolveQuestion(arg: string, questions: QuestionMap): string[] { + // Exact ID match + if (arg in questions) + return [arg]; + + // Pattern match: section-q-n + if (/^\w+-q-\d+$/.test(arg)) + return []; // matched pattern but not found + + // Case-insensitive label substring search + const lower = arg.toLowerCase(); + return Object.entries(questions) + .filter(([, q]) => q.label.toLowerCase().includes(lower)) + .map(([id]) => id); +} + +function resolveFilter(raw: string, questions: QuestionMap): { questionId: string; choiceIndex: number } { + const eq = raw.indexOf("="); + if (eq === -1) { + console.error(`Error: invalid filter "${raw}" — expected format: question=choice`); + process.exit(1); + } + const qPart = raw.slice(0, eq); + const cPart = raw.slice(eq + 1); + + const qMatches = resolveQuestion(qPart, questions); + if (qMatches.length === 0) { + console.error(`Error: no question found matching filter "${qPart}"`); + process.exit(1); + } + if (qMatches.length > 1) { + console.error(`Error: ambiguous filter question "${qPart}" — matches:\n`); + for (const id of qMatches) console.error(` ${id} → ${questions[id].label}`); + process.exit(1); + } + + const questionId = qMatches[0]; + const meta = questions[questionId]; + + // Numeric string → treat as choice index + if (/^\d+$/.test(cPart)) + return { questionId, choiceIndex: Number(cPart) }; + + const idx = meta.choices.findIndex(c => c.toLowerCase().includes(cPart.toLowerCase())); + if (idx === -1) { + console.error(`Error: no choice found matching "${cPart}" in question "${meta.label}"`); + console.error(` choices: ${meta.choices.map((c, i) => `${i}: ${c}`).join(" | ")}`); + process.exit(1); + } + return { questionId, choiceIndex: idx }; +} + +function computeStats(id: string, meta: Question, results: ResultEntry[], filteredCount: number) { + const choices = meta.choices.map((label, i) => ({ label, index: i, count: 0 })); + let total = 0; + + for (const entry of results) { + const val = entry[id]; + if (val === null || val === undefined) + continue; + total++; + const indices = Array.isArray(val) ? val : [val]; + for (const idx of indices) { + if (typeof idx === "number" && choices[idx]) + choices[idx].count++; + } + } + + return { + id, + question: meta.label, + multiple: meta.multiple, + total, + skipped: filteredCount - total, + choices: choices.map(({ label, count }) => ({ + label, + count, + percentage: total > 0 ? Math.round((count / total) * 1000) / 10 : 0 + })) + }; +} + +interface FilterInfo { question: string; choice: string } + +function formatText( + stats: ReturnType, + year: string, + filters: FilterInfo[] +) { + const lines: string[] = []; + if (filters.length > 0) { + lines.push(`Filtered by: ${filters.map(f => `${f.question} = ${f.choice}`).join(", ")}`); + } + lines.push( + `[${year}] ${stats.question} (${stats.id})`, + `Total: ${stats.total} answered, ${stats.skipped} skipped`, + "", + ...stats.choices.map( + c => ` ${c.label.padEnd(40)} ${String(c.count).padStart(5)} ${c.percentage.toFixed(1)}%` + ) + ); + return lines.join("\n"); +} + +function main() { + const args = process.argv.slice(2); + + if (args.length === 0) { + console.error("Usage: pnpm query-results [--year=YYYY] [--format=text|json] [--filter=question=choice]"); + process.exit(1); + } + + let query = ""; + let year = ""; + let format = "json"; + const filterArgs: string[] = []; + + for (const arg of args) { + if (arg.startsWith("--year=")) + year = arg.slice(7); + else if (arg.startsWith("--format=")) + format = arg.slice(9); + else if (arg.startsWith("--filter=")) + filterArgs.push(arg.slice(9)); + else query = arg; + } + + if (!query) { + console.error("Error: missing question argument"); + process.exit(1); + } + + const resultsDir = path.resolve(process.cwd(), "results"); + if (!year) + year = getLatestYear(resultsDir); + + const { questions, results: rawResults } = loadData(year); + const matches = resolveQuestion(query, questions); + + if (matches.length === 0) { + console.error(`No question found matching "${query}" in ${year}`); + process.exit(1); + } + + if (matches.length > 1) { + console.error(`Multiple matches for "${query}" — narrow down with one of:\n`); + for (const id of matches) { + console.error(` ${id} → ${questions[id].label}`); + } + process.exit(1); + } + + const id = matches[0]; + + // Apply filters by pre-filtering the results array + const resolvedFilters = filterArgs.map(f => resolveFilter(f, questions)); + let results = rawResults; + for (const f of resolvedFilters) { + results = results.filter((entry) => { + const val = entry[f.questionId]; + if (val === null || val === undefined) + return false; + const selected = Array.isArray(val) ? (val as number[]) : [val as number]; + return selected.includes(f.choiceIndex); + }); + } + + const filters: FilterInfo[] = resolvedFilters.map(f => ({ + question: questions[f.questionId].label, + choice: questions[f.questionId].choices[f.choiceIndex] + })); + + const stats = computeStats(id, questions[id], results, results.length); + + if (format === "text") { + console.log(formatText(stats, year, filters)); + } + else { + const output = { + ...stats, + year: Number(year), + ...(filters.length > 0 && { filters }) + }; + console.log(JSON.stringify(output, null, 2)); + } +} + +main(); diff --git a/src/components/report/hero.astro b/src/components/report/hero.astro index 24906320..ecfb65cf 100644 --- a/src/components/report/hero.astro +++ b/src/components/report/hero.astro @@ -52,8 +52,11 @@ const data = { }, 2025: { year: 2025, - description: `this is the 2025 report`, - episode_url: `https://www.youtube.com/embed/vAl-Xou-CrU` + description: `In December 2025, 1007 developers from Morocco 🇲🇦 + told us about their jobs satisfaction, salaries, and community + contribution, what they think about AI, which tools they're + using, and what they want to learn next.`, + episode_url: `https://www.youtube.com/embed/iigsuJ4YP44` } } as const; diff --git a/src/components/report/index.astro b/src/components/report/index.astro index 38165821..d0f19bd4 100644 --- a/src/components/report/index.astro +++ b/src/components/report/index.astro @@ -3,6 +3,7 @@ import type { Year } from "@/components/chart/data"; import Context from "@astro-utils/context/Context.astro"; import Chart from "@/components/chart/chart.astro"; import Hero from "./hero.astro"; +import New from "./new-badge.astro"; import TabItem from "./tab-item.astro"; import Tabs from "./tabs.astro"; @@ -26,6 +27,7 @@ const headings = docs .filter(heading => heading.depth <= 3); const customComponents = { Chart, + New, TabItem, Tabs }; diff --git a/src/components/report/new-badge.astro b/src/components/report/new-badge.astro new file mode 100644 index 00000000..0ff80e7a --- /dev/null +++ b/src/components/report/new-badge.astro @@ -0,0 +1,3 @@ +--- +--- +New diff --git a/src/pages/2025.astro b/src/pages/2025.astro new file mode 100644 index 00000000..0c674aa8 --- /dev/null +++ b/src/pages/2025.astro @@ -0,0 +1,11 @@ +--- +import BaseLayout from "@/components/layout.astro"; + +import Report from "@/components/report/index.astro"; + +export const prerender = true; +--- + + + + diff --git a/src/pages/index.astro b/src/pages/index.astro index 8dc15bff..24f141a9 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,8 +1,7 @@ --- -import Report2024 from "./2024.astro"; -// import Home from "./home.astro"; +import Report2025 from "./2025.astro"; export const prerender = true; --- - +