From a5918c7e14d6a1507ff32864f0235fc1d2dfe476 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 26 Apr 2025 19:26:08 -0400 Subject: [PATCH 1/1] initial template --- .eslintrc.js | 221 ++++++++++++++++++++++++++++++++++++++++++++ .gitignore | 15 +++ .html-minifier.conf | 27 ++++++ .prettierrc.js | 10 ++ .terser.json | 8 ++ README.md | 1 + UNLICENSE | 24 +++++ css/options.css | 8 ++ html/options.html | 10 ++ images/icon-128.png | 0 images/icon-16.png | 0 images/icon-48.png | 0 js/background.js | 5 + js/options.js | 5 + manifest-files.py | 49 ++++++++++ manifest.files | 3 + manifest.json | 23 +++++ package.json | 45 +++++++++ postcss.config.js | 7 ++ 19 files changed, 461 insertions(+) create mode 100644 .eslintrc.js create mode 100644 .gitignore create mode 100644 .html-minifier.conf create mode 100644 .prettierrc.js create mode 100644 .terser.json create mode 100644 README.md create mode 100644 UNLICENSE create mode 100644 css/options.css create mode 100644 html/options.html create mode 100644 images/icon-128.png create mode 100644 images/icon-16.png create mode 100644 images/icon-48.png create mode 100644 js/background.js create mode 100644 js/options.js create mode 100755 manifest-files.py create mode 100644 manifest.files create mode 100644 manifest.json create mode 100644 package.json create mode 100644 postcss.config.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..d12a929 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,221 @@ +// Copyright 2021 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module.exports = { + root: true, + env: { + browser: true, + // This allows the runtime environment (i.e. objects). + es6: true, + }, + parserOptions: { + // This sets the syntax parsing level. + ecmaVersion: 2020, + sourceType: 'module', + }, + + plugins: ['jsdoc'], + + // See https://eslint.org/docs/rules/ for details. + // These rules were picked based on the existing codebase. If you find one + // to be too onerous and not required by the styleguide, feel free to discuss. + rules: { + 'array-bracket-spacing': 'error', + 'arrow-parens': ['error', 'always'], + 'arrow-spacing': ['error', {before: true, after: true}], + 'block-spacing': ['error', 'always'], + 'comma-dangle': ['error', 'always-multiline'], + 'comma-spacing': 'error', + 'comma-style': 'error', + 'curly': 'error', + 'default-param-last': 'error', + 'eol-last': 'error', + 'func-call-spacing': 'error', + 'generator-star-spacing': ['error', 'after'], + // l/I: Depending on the font, these are hard to distinguish. + 'id-blacklist': ['error', 'l', 'I', 'self'], + 'keyword-spacing': 'error', + 'lines-between-class-members': 'error', + 'max-len': ['error', {code: 80, ignoreUrls: true}], + 'new-parens': 'error', + 'no-alert': 'error', + 'no-case-declarations': 'error', + 'no-cond-assign': 'error', + 'no-const-assign': 'error', + 'no-control-regex': 'error', + 'no-debugger': 'error', + 'no-dupe-args': 'error', + 'no-dupe-class-members': 'error', + 'no-dupe-keys': 'error', + 'no-duplicate-case': 'error', + 'no-empty': 'error', + 'no-empty-character-class': 'error', + 'no-eval': 'error', + 'no-ex-assign': 'error', + // We want 'all' (nestedBinaryExpressions=false), but this breaks + // closure-compiler casts. + 'no-extra-parens': ['error', 'functions'], + 'no-extra-semi': 'error', + 'no-implied-eval': 'error', + 'no-invalid-regexp': 'error', + 'no-irregular-whitespace': 'error', + 'no-label-var': 'error', + 'no-mixed-spaces-and-tabs': 'error', + 'no-multi-spaces': ['error', {ignoreEOLComments: true}], + 'no-multiple-empty-lines': 'error', + 'no-new': 'error', + 'no-new-func': 'error', + 'no-new-object': 'error', + 'no-new-wrappers': 'error', + 'no-obj-calls': 'error', + 'no-octal': 'error', + 'no-octal-escape': 'error', + 'no-return-await': 'error', + 'no-script-url': 'error', + 'no-self-assign': 'error', + 'no-self-compare': 'error', + 'no-sequences': 'error', + 'no-shadow-restricted-names': 'error', + 'no-tabs': 'error', + 'no-template-curly-in-string': 'error', + 'no-throw-literal': 'error', + 'no-trailing-spaces': 'error', + 'no-unmodified-loop-condition': 'error', + 'no-unneeded-ternary': 'error', + 'no-unreachable': 'error', + 'no-useless-call': 'error', + 'no-useless-concat': 'error', + 'no-useless-escape': 'error', + 'no-useless-return': 'error', + 'no-var': 'error', + 'no-void': 'error', + // We allow TODO comments. + 'no-warning-comments': [ + 'error', + { + terms: ['fix', 'fixme', 'xxx'], + }, + ], + 'no-whitespace-before-property': 'error', + 'no-with': 'error', + 'object-curly-newline': ['error', {consistent: true}], + 'object-curly-spacing': 'error', + 'one-var-declaration-per-line': 'error', + 'prefer-const': 'error', + 'prefer-numeric-literals': 'error', + 'prefer-rest-params': 'error', + 'quote-props': ['error', 'consistent'], + 'quotes': [ + 'error', + 'single', + {avoidEscape: true, allowTemplateLiterals: true}, + ], + 'radix': 'error', + 'rest-spread-spacing': 'error', + 'semi': ['error', 'always'], + 'semi-spacing': 'error', + 'semi-style': ['error', 'last'], + 'space-before-blocks': ['error', 'always'], + 'space-before-function-paren': [ + 'error', + { + anonymous: 'never', + named: 'never', + asyncArrow: 'always', + }, + ], + 'space-in-parens': ['error', 'never'], + 'space-infix-ops': 'error', + 'space-unary-ops': 'error', + 'spaced-comment': ['error', 'always'], + 'switch-colon-spacing': ['error', {after: true, before: false}], + 'symbol-description': 'error', + 'template-curly-spacing': ['error', 'never'], + 'unicode-bom': ['error', 'never'], + 'use-isnan': 'error', + 'valid-typeof': 'error', + 'yield-star-spacing': ['error', 'after'], + 'yoda': 'error', + + 'jsdoc/check-access': 'error', + 'jsdoc/check-alignment': 'error', + 'jsdoc/check-examples': 'error', + // We want hanging indentation, but this check requires none everywhere. + 'jsdoc/check-indentation': 'off', + 'jsdoc/check-param-names': 'error', + 'jsdoc/check-property-names': 'error', + // Make sure this is disabled as this rejects closure syntax. + 'jsdoc/check-syntax': 'off', + 'jsdoc/check-tag-names': 'error', + // This is disabled until this crash is resolved: + // https://github.com/gajus/eslint-plugin-jsdoc/issues/389 + 'jsdoc/check-types': 'off', + // We don't use these tags in the project. + 'jsdoc/check-values': 'off', + 'jsdoc/empty-tags': 'error', + 'jsdoc/implements-on-classes': 'error', + // Can't turn on until require-description is enabled. + 'jsdoc/match-description': 'off', + 'jsdoc/newline-after-description': 'error', + // This is only for TypeScript which we don't care about. + 'jsdoc/no-types': 'off', + // This would be nice to turn on, but requires a lot more research. + // See valid-types setting below too. + 'jsdoc/no-undefined-types': 'off', + // TODO(vapier): Turn this on. + 'jsdoc/require-description': 'off', + // TODO(vapier): Turn this on. + 'jsdoc/require-description-complete-sentence': 'off', + // We don't want to require examples. + 'jsdoc/require-example': 'off', + // TODO(vapier): Turn this on. + 'jsdoc/require-file-overview': 'off', + 'jsdoc/require-hyphen-before-param-description': ['error', 'never'], + // TODO(vapier): Turn this on. + 'jsdoc/require-jsdoc': 'off', + 'jsdoc/require-param': 'off', + // TODO(vapier): Turn this on. + 'jsdoc/require-param-description': 'off', + 'jsdoc/require-param-name': 'error', + 'jsdoc/require-param-type': 'error', + 'jsdoc/require-returns': 'off', + 'jsdoc/require-returns-check': 'error', + // TODO(vapier): Turn this on. + 'jsdoc/require-returns-description': 'off', + 'jsdoc/require-returns-type': 'error', + // This would be nice to turn on, but requires a lot more research. + 'jsdoc/valid-types': 'off', + }, + + settings: { + // https://github.com/BenoitZugmeyer/eslint-plugin-html#settings + html: { + // TODO(vapier): Would like to use .html.in, but doesn't work right. + // https://github.com/BenoitZugmeyer/eslint-plugin-html/issues/127 + 'html-extensions': ['.html', '.in'], + }, + + // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc + jsdoc: { + mode: 'closure', + preferredTypes: { + object: 'Object', + }, + tagNamePreference: { + // While not explicitly defined, Google/Chromium JS style guides only + // use these keyword forms, as does the closure compiler docs. + augments: 'extends', + constant: 'const', + class: 'constructor', + file: 'fileoverview', + returns: 'return', + yields: 'yield', + + // Stub out closure-specific tags so they get ignored. + // TODO(vapier): Delete this after upgrade to newer jsdoc. + closurePrimitive: '', + }, + }, + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89df27f --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Various temp files and editor configs. +*~ +\#* +.#* +*.swp +.eslintcache +.vscode + +# Stuff we build for distribution. +dist +*.zip + +# npm related dirs. +node_modules +package-lock.json diff --git a/.html-minifier.conf b/.html-minifier.conf new file mode 100644 index 0000000..21a31cc --- /dev/null +++ b/.html-minifier.conf @@ -0,0 +1,27 @@ +{ + "collapseBooleanAttributes": true, + "collapseWhitespace": true, + "customAttrCollapse": ".*", + "decodeEntities": true, + "html5": true, + "includeAutoGeneratedTags": false, + "keepClosingSlash": false, + "maxLineLength": 0, + "processConditionalComments": true, + "processScripts": [ + "text/html" + ], + "removeAttributeQuotes": true, + "removeComments": true, + "removeEmptyAttributes": true, + "removeEmptyElements": true, + "removeOptionalTags": true, + "removeRedundantAttributes": true, + "removeScriptTypeAttributes": true, + "removeStyleLinkTypeAttributes": true, + "removeTagWhitespace": true, + "sortAttributes": true, + "sortClassName": true, + "trimCustomFragments": true, + "useShortDoctype": true +} diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..245d4f3 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,10 @@ +// Copyright 2021 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module.exports = { + bracketSpacing: false, + trailingComma: 'all', + quoteProps: 'consistent', + singleQuote: true, +}; diff --git a/.terser.json b/.terser.json new file mode 100644 index 0000000..f661b00 --- /dev/null +++ b/.terser.json @@ -0,0 +1,8 @@ +{ + "compress": { + "unused": false + }, + "ecma": 2024, + "mangle": false, + "module": true +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..8f6ba0b --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Template for Chrome extensions. diff --git a/UNLICENSE b/UNLICENSE new file mode 100644 index 0000000..efb9808 --- /dev/null +++ b/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/css/options.css b/css/options.css new file mode 100644 index 0000000..4f82c66 --- /dev/null +++ b/css/options.css @@ -0,0 +1,8 @@ +/** + * Styles used by the options page. + * + * Written by Mike Frysinger . Released into the public domain. + */ + +@media (prefers-color-scheme: dark) { +} diff --git a/html/options.html b/html/options.html new file mode 100644 index 0000000..4c21677 --- /dev/null +++ b/html/options.html @@ -0,0 +1,10 @@ + + + + + Options + + + + + diff --git a/images/icon-128.png b/images/icon-128.png new file mode 100644 index 0000000..e69de29 diff --git a/images/icon-16.png b/images/icon-16.png new file mode 100644 index 0000000..e69de29 diff --git a/images/icon-48.png b/images/icon-48.png new file mode 100644 index 0000000..e69de29 diff --git a/js/background.js b/js/background.js new file mode 100644 index 0000000..5cd428c --- /dev/null +++ b/js/background.js @@ -0,0 +1,5 @@ +// Written by Mike Frysinger . Released into the public domain. + +/** + * @fileoverview Code for the background page. + */ diff --git a/js/options.js b/js/options.js new file mode 100644 index 0000000..31567c1 --- /dev/null +++ b/js/options.js @@ -0,0 +1,5 @@ +// Written by Mike Frysinger . Released into the public domain. + +/** + * @fileoverview Code for the options page. + */ diff --git a/manifest-files.py b/manifest-files.py new file mode 100755 index 0000000..944bbec --- /dev/null +++ b/manifest-files.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# Written by Mike Frysinger . Released into the public domain. + +import argparse +import fnmatch +import json +import sys + + +def get_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--filter", default="*") + parser.add_argument("manifest", nargs="?", default="manifest.json") + parser.add_argument("filelist", nargs="?", default="manifest.files") + return parser + + +def main(argv: list[str]) -> int | None: + parser = get_parser() + opts = parser.parse_args(argv) + + with open(opts.manifest) as fp: + data = json.load(fp) + + files = set(data["icons"].values()) + for script in data.get("content_scripts", []): + files.update(script.get("css", ())) + files.update(script.get("js", ())) + files.add(data["background"]["service_worker"]) + files.add(data["options_ui"]["page"]) + + with open(opts.filelist) as fp: + for line in fp: + line = line.split("#", 1)[0].strip() + if not line: + continue + if line in files: + print( + "warning: redundant entry in %s: %s" % (opts.filelist, line), + file=sys.stderr, + ) + else: + files.add(line) + + print("\n".join(sorted(x for x in files if fnmatch.fnmatch(x, opts.filter)))) + + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:])) diff --git a/manifest.files b/manifest.files new file mode 100644 index 0000000..da0e4e9 --- /dev/null +++ b/manifest.files @@ -0,0 +1,3 @@ +# List of files to include in the extension. Files listed in the manifest.json +# are automatically included and do not need listing here. +css/options.css diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..3966eeb --- /dev/null +++ b/manifest.json @@ -0,0 +1,23 @@ +{ + "key": "", + "short_name": "", + "name": "", + "description": "", + "version": "0.0.0", + "manifest_version": 3, + "icons": { + "16": "images/icon-16.png", + "48": "images/icon-48.png", + "128": "images/icon-128.png" + }, + "options_ui": { + "page": "html/options.html", + "open_in_tab": false + }, + "permissions": [], + "action": {}, + "background": { + "type": "module", + "service_worker": "js/background.js" + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..46fa0b2 --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "", + "version": "0.0.0", + "author": "vapier@gmail.com", + "license": "Unlicense", + "scripts": { + "ci": "npm-run-all --parallel 'format:* -- --check' lint", + "dist": "rm -rf dist ext.zip && mkdir -p dist/css dist/fonts dist/html dist/images dist/js && npm-run-all --parallel dist:* && cd dist && zip -r ../ext.zip .", + "dist:css": "postcss `./manifest-files.py --filter 'css/*.css'` --dir dist/css/", + "dist:fonts": "[ -d fonts ] || exit 0; cp `./manifest-files.py --filter 'fonts/*'` dist/fonts/", + "dist:html": "set -e; for f in `./manifest-files.py --filter '*.html'`; do html-minifier -c .html-minifier.conf $f >dist/$f; done", + "dist:js": "set -e; for f in `./manifest-files.py --filter '*.js'`; do terser --config-file .terser.json $f --output dist/$f; done", + "dist:json": "sed '/\"key\":/d' manifest.json | json-minify >dist/manifest.json", + "dist:images": "cp `./manifest-files.py --filter 'images/*'` dist/images/", + "fix": "npm-run-all --parallel fix:*", + "fix:js": "eslint --cache --fix js/*.js", + "format": "npm-run-all --parallel 'format:* -- --write'", + "format:css": "prettier css/*.css", + "format:js": "prettier js/*.js .*.js *.js", + "format:json": "prettier *.json", + "format:html": "prettier html/*.html", + "format:md": "prettier *.md", + "format:py": "black *.py #", + "lint": "npm-run-all --parallel lint:*", + "lint:js": "eslint --cache js/*.js", + "lint:md": "markdownlint *.md", + "release": "npm-run-all --parallel ci dist", + "start": "http-server -a localhost -c-1 --cors ." + }, + "devDependencies": { + "cssnano": "~7", + "eslint": "~9", + "eslint-plugin-jsdoc": "~50", + "html-minifier": "~4", + "http-server": "~14", + "json-minify": "^1.0.0", + "markdownlint-cli": "~0", + "npm-run-all": "~4", + "postcss": "~8", + "postcss-cli": "~8", + "prettier": "~3", + "terser": "~5" + }, + "dependencies": {} +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..c4cf788 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,7 @@ +module.exports = { + plugins: [ + require('cssnano')({ + preset: 'default', + }), + ], +}; -- 2.39.5