diff --git a/.claude/rules/edge-apps.md b/.claude/rules/edge-apps.md index d66d6a0cf..820c0aeac 100644 --- a/.claude/rules/edge-apps.md +++ b/.claude/rules/edge-apps.md @@ -103,8 +103,7 @@ document.addEventListener('DOMContentLoaded', async () => { - Avoid using `!important` as it breaks the natural cascading behavior of CSS. Instead, use more specific selectors or leverage CSS custom properties (variables) for values that need to be overridden. - Use CSS custom properties (variables) for theme values, colors, and other design tokens that need to be overridden. - Do not add code comments to CSS code unless it's not obvious what the code does. -- This project uses [Super Linter](mdc:https://github.com/github/super-linter) for linting. - - Stylelint is used for linting CSS files. +- Stylelint is used for linting CSS files. - Use Stylelint's rules ([https://stylelint.io/user-guide/rules](https://stylelint.io/user-guide/rules)) as a guide when generating code. ## SCSS diff --git a/.github/linters/.jscpd.json b/.github/linters/.jscpd.json deleted file mode 100644 index 1b9fd23dd..000000000 --- a/.github/linters/.jscpd.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "threshold": 0, - "reporters": [ - "consoleFull" - ], - "ignore": [ - "**/__snapshots__/**", - "**/*.html", - "**/*.css", - "**/*.svg" - ], - "absolute": true -} diff --git a/.github/linters/.prettierrc.json b/.github/linters/.prettierrc.json deleted file mode 100644 index b2095be81..000000000 --- a/.github/linters/.prettierrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "semi": false, - "singleQuote": true -} diff --git a/.github/linters/.textlintrc b/.github/linters/.textlintrc deleted file mode 100644 index edd389ddf..000000000 --- a/.github/linters/.textlintrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "filters": { - "comments": true - }, - "rules": { - "terminology": { - "severity": "warning" - } - } -} diff --git a/.github/linters/.yamllint.yml b/.github/linters/.yamllint.yml deleted file mode 100644 index ccc7a6693..000000000 --- a/.github/linters/.yamllint.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -extends: default - -rules: - # 80 chars should be enough, but don't fail if a line is longer - line-length: - max: 80 - level: warning - diff --git a/.github/linters/stylelint.config.cjs b/.github/linters/stylelint.config.cjs deleted file mode 100644 index e6308852d..000000000 --- a/.github/linters/stylelint.config.cjs +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - overrides: [ - { - files: ['**/*.scss'], - customSyntax: 'postcss-scss' - } - ], - rules: { - 'media-feature-range-notation': 'prefix' - } -} diff --git a/.github/workflows/edge-app-checks.yml b/.github/workflows/edge-app-checks.yml index 0938690d1..282ebecb4 100644 --- a/.github/workflows/edge-app-checks.yml +++ b/.github/workflows/edge-app-checks.yml @@ -19,6 +19,7 @@ jobs: outputs: changed-apps: ${{ steps.extract-changes.outputs.changed-apps }} apps-with-build-system: ${{ steps.build-system-check.outputs.apps-with-build-system }} + apps-without-build-system: ${{ steps.no-build-system-check.outputs.apps-without-build-system }} steps: - name: Checkout code uses: actions/checkout@v6 @@ -46,12 +47,12 @@ jobs: # Read CHANGED_FILES into an array read -ra FILES_ARRAY <<< "$CHANGED_FILES" - # Function to add app to list if it has build system and isn't already included + # Function to add app to list if not already included add_app_if_valid() { local app="$1" if [[ -n "$app" && "$app" != "helpers" && "$app" != ".bun-create" ]]; then - if [[ -f "edge-apps/$app/package.json" ]]; then - if [[ ! " $CHANGED_APPS " =~ $app ]]; then + if [[ -d "edge-apps/$app" ]]; then + if [[ " $CHANGED_APPS " != *" $app "* ]]; then CHANGED_APPS="$CHANGED_APPS $app" fi fi @@ -99,8 +100,30 @@ jobs: fi echo "Apps with build system: $APPS_WITH_BUILD_SYSTEM" - run-checks: - name: Run Checks for ${{ matrix.app }} + - name: Check which apps don't have build systems + id: no-build-system-check + run: | + CHANGED_APPS="${{ steps.extract-changes.outputs.changed-apps }}" + APPS_WITHOUT_BUILD_SYSTEM="" + + read -ra APPS_ARRAY <<< "$CHANGED_APPS" + for app in "${APPS_ARRAY[@]}"; do + if [[ ! -f "edge-apps/$app/package.json" ]]; then + APPS_WITHOUT_BUILD_SYSTEM="$APPS_WITHOUT_BUILD_SYSTEM $app" + fi + done + + APPS_WITHOUT_BUILD_SYSTEM="${APPS_WITHOUT_BUILD_SYSTEM# }" + if [[ -n "$APPS_WITHOUT_BUILD_SYSTEM" ]]; then + JSON_ARRAY=$(echo "$APPS_WITHOUT_BUILD_SYSTEM" | tr ' ' '\n' | jq -R . | jq -s -c .) + echo "apps-without-build-system=$JSON_ARRAY" >> "$GITHUB_OUTPUT" + else + echo "apps-without-build-system=[]" >> "$GITHUB_OUTPUT" + fi + echo "Apps without build system: $APPS_WITHOUT_BUILD_SYSTEM" + + run-full-checks: + name: Run Full Checks for ${{ matrix.app }} runs-on: ubuntu-latest needs: detect-changes strategy: @@ -162,24 +185,81 @@ jobs: retry_on: error command: cd edge-apps/${{ matrix.app }} && bun run test:e2e + run-simple-checks: + name: Run Simple Checks for ${{ matrix.app }} + runs-on: ubuntu-latest + needs: detect-changes + strategy: + matrix: + app: ${{ fromJSON(needs.detect-changes.outputs.apps-without-build-system) }} + fail-fast: false + if: needs.detect-changes.outputs.apps-without-build-system != '[]' + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.2.2 + + - name: Run formatting check + run: | + bunx prettier --check \ + --config edge-apps/.prettierrc.json \ + "edge-apps/${{ matrix.app }}/**/*.{html,css,js,json,yml,yaml,md}" + + - name: Run Markdown lint + run: | + bunx markdownlint-cli2 "edge-apps/${{ matrix.app }}/**/*.md" + + - name: Run HTML lint + run: | + find "edge-apps/${{ matrix.app }}" \ + -name "*.html" \ + -not -path "*/static/*" \ + -not -path "*/dist/*" \ + -not -path "*/node_modules/*" \ + -print0 | xargs -0 -r bunx htmlhint + + - name: Run CSS lint + run: | + find "edge-apps/${{ matrix.app }}" \ + -name "*.css" \ + -not -path "*/dist/*" \ + -not -path "*/node_modules/*" \ + -print0 | xargs -0 -r bunx stylelint \ + --config edge-apps/.stylelintrc.json + + - name: Run JavaScript lint + run: | + find "edge-apps/${{ matrix.app }}" \ + -name "*.js" \ + -not -name "*.min.js" \ + -not -name "eslint.config.js" \ + -not -path "*/dist/*" \ + -not -path "*/node_modules/*" \ + -print0 | xargs -0 -r bunx eslint \ + --config edge-apps/eslint.config.cjs + summary: name: Summary runs-on: ubuntu-latest - needs: [detect-changes, run-checks] + needs: [detect-changes, run-full-checks, run-simple-checks] if: always() steps: - name: Check if any apps were processed run: | if [[ "${{ needs.detect-changes.outputs.changed-apps }}" == "" ]]; then echo "No Edge Apps were changed." - elif [[ "${{ needs.detect-changes.outputs.apps-with-build-system }}" == "[]" ]]; then - echo "Changed Edge Apps don't have build systems: ${{ needs.detect-changes.outputs.changed-apps }}" else - echo "Processed Edge Apps with build systems: ${{ needs.detect-changes.outputs.apps-with-build-system }}" + echo "Apps with build system: ${{ needs.detect-changes.outputs.apps-with-build-system }}" + echo "Apps without build system: ${{ needs.detect-changes.outputs.apps-without-build-system }}" fi - name: Check for failures - if: needs.run-checks.result == 'failure' + if: needs.run-full-checks.result == 'failure' || needs.run-simple-checks.result == 'failure' run: | echo "Some Edge App checks failed. Please review the logs above." exit 1 diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml deleted file mode 100644 index abf696aaf..000000000 --- a/.github/workflows/linter.yml +++ /dev/null @@ -1,79 +0,0 @@ ---- -################################# -################################# -## Super Linter GitHub Actions ## -################################# -################################# -name: Lint Code Base - -# -# Documentation: -# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions -# - -############################# -# Start the job on all push # -############################# -on: - push: - branches-ignore: [master, main] - # Remove the line above to run when pushing to master - pull_request: - branches: [master, main] - -############### -# Set the Job # -############### -jobs: - build: - # Name the Job - name: Lint Code Base - # Set the agent to run on - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: read - - ################## - # Load all steps # - ################## - steps: - ########################## - # Checkout the code base # - ########################## - - name: Checkout Code - uses: actions/checkout@v6 - with: - # Full git history is needed to get a proper list of changed files within `super-linter` - fetch-depth: 0 - persist-credentials: false - - ################################ - # Run Linter against code base # - ################################ - - name: Lint Code Base - uses: super-linter/super-linter@9e863354e3ff62e0727d37183162c4a88873df41 - env: - VALIDATE_ALL_CODEBASE: false - VALIDATE_BIOME_FORMAT: false - VALIDATE_BIOME_LINT: false - VALIDATE_EDITORCONFIG: false - VALIDATE_HTML: false - VALIDATE_TYPESCRIPT_ES: false - VALIDATE_TYPESCRIPT_PRETTIER: false - VALIDATE_TYPESCRIPT_STANDARD: false - VALIDATE_VUE: false - VALIDATE_VUE_PRETTIER: false - VALIDATE_JSCPD: false - VALIDATE_CHECKOV: false - VALIDATE_TRIVY: false - VALIDATE_GITHUB_ACTIONS_ZIZMOR: false - CSS_FILE_NAME: stylelint.config.cjs - DEFAULT_BRANCH: master - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - FILTER_REGEX_EXCLUDE: '.*edge-apps/powerbi-legacy/.*' - PRETTIER_COMMAND_OPTIONS: '--config .github/linters/.prettierrc.json --check' - ENABLE_GITHUB_ACTIONS_GROUP_TITLE: false - ENABLE_GITHUB_PULL_REQUEST_SUMMARY_COMMENT: false - ENABLE_GITHUB_ACTIONS_STEP_SUMMARY: false - VALIDATE_SPELL_CODESPELL: false diff --git a/edge-apps/.stylelintrc.json b/edge-apps/.stylelintrc.json new file mode 100644 index 000000000..1a7674413 --- /dev/null +++ b/edge-apps/.stylelintrc.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://json.schemastore.org/stylelintrc", + "rules": { + "color-no-invalid-hex": true, + "declaration-block-no-duplicate-properties": true, + "no-duplicate-selectors": true, + "no-empty-source": true, + "unit-no-unknown": true + } +} diff --git a/edge-apps/README.md b/edge-apps/README.md index 8e1c28d13..7b9feafa9 100644 --- a/edge-apps/README.md +++ b/edge-apps/README.md @@ -28,6 +28,41 @@ After scaffolding: bun run dev ``` +## Linting and Formatting + +### Apps with a build system + +From the app directory, run: + +```bash +bun run lint +bun run format:check +``` + +### Apps without a build system + +From the repository root, run the following tools via `bunx`: + +```bash +# Formatting (HTML, CSS, JS, JSON, YAML, Markdown) +bunx prettier --check --config edge-apps/.prettierrc.json "edge-apps//**/*.{html,css,js,json,yml,yaml,md}" + +# Markdown +bunx markdownlint-cli2 "edge-apps//**/*.md" + +# HTML +bunx htmlhint "edge-apps//index.html" + +# CSS (excludes dist/) +find edge-apps/ -name "*.css" -not -path "*/dist/*" -not -path "*/node_modules/*" \ + -print0 | xargs -0 -r bunx stylelint --config edge-apps/.stylelintrc.json + +# JavaScript (excludes dist/ and minified files) +find edge-apps/ -name "*.js" -not -name "*.min.js" -not -name "eslint.config.js" \ + -not -path "*/dist/*" -not -path "*/node_modules/*" \ + -print0 | xargs -0 -r bunx eslint --config edge-apps/eslint.config.cjs +``` + ## TypeScript Library The [`@screenly/edge-apps`](https://www.npmjs.com/package/@screenly/edge-apps) NPM package contains shared utilities, components, and styles used by the apps in this directory. diff --git a/edge-apps/eslint.config.cjs b/edge-apps/eslint.config.cjs new file mode 100644 index 000000000..744896466 --- /dev/null +++ b/edge-apps/eslint.config.cjs @@ -0,0 +1,26 @@ +/** @type {import('eslint').Linter.Config[]} */ +module.exports = [ + { + languageOptions: { + ecmaVersion: 2020, + sourceType: 'script', + globals: { + window: 'readonly', + document: 'readonly', + console: 'readonly', + fetch: 'readonly', + screenly: 'readonly', + setTimeout: 'readonly', + setInterval: 'readonly', + clearTimeout: 'readonly', + clearInterval: 'readonly', + alert: 'readonly', + location: 'readonly', + }, + }, + rules: { + 'no-undef': 'error', + 'no-unused-vars': 'warn', + }, + }, +]