mirror of
https://github.com/discourse/discourse.git
synced 2026-09-05 04:40:41 -05:00
DEV: add typescript support for core, themes and plugins (#41478)
We've been using basic type-checking via JSDoc for some time. This commit allows us to author proper `.ts`/`.gts` files, and use the full typescript syntax. Initially, only d-button and a single chat file are migrated, as proof of functionality. In future, we may migrate more files, and consider making our tsconfig more strict.
This commit is contained in:
@@ -26,3 +26,4 @@ tmp/
|
||||
**/*.json
|
||||
!**/tsconfig.json
|
||||
**/*.md
|
||||
**/*.d.ts
|
||||
|
||||
@@ -12,8 +12,8 @@ PROJECT_ROOT = File.expand_path("..", __dir__)
|
||||
# live outside the core repo (e.g. plugins/*) where lefthook is not available.
|
||||
class ExternalLinter
|
||||
RUBY_EXTENSIONS = %w[rb rake thor].freeze
|
||||
PRETTIER_EXTENSIONS = %w[css scss js gjs cjs mjs].freeze
|
||||
ESLINT_EXTENSIONS = %w[js gjs].freeze
|
||||
PRETTIER_EXTENSIONS = %w[css scss js gjs cjs mjs ts gts mts cts].freeze
|
||||
ESLINT_EXTENSIONS = %w[js gjs ts gts mts cts].freeze
|
||||
STYLELINT_EXTENSIONS = %w[scss].freeze
|
||||
|
||||
JS_EXTENSIONS = (PRETTIER_EXTENSIONS + ESLINT_EXTENSIONS + STYLELINT_EXTENSIONS).uniq.freeze
|
||||
@@ -239,7 +239,7 @@ class LefthookLinter
|
||||
end
|
||||
|
||||
# Check if file extension is lintable
|
||||
lintable_extensions = %w[rb rake js gjs hbs scss css yml yaml thor]
|
||||
lintable_extensions = %w[rb rake js gjs ts gts mts cts hbs scss css yml yaml thor]
|
||||
lintable_extensions.include?(ext)
|
||||
end
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ Discourse ships type information for its JavaScript code. This can provide inlin
|
||||
|
||||
Much of this will be automatically consumed by IDEs with TypeScript/JavaScript support. But for functionality in `.gjs` files, you'll need some specific configuration and/or IDE plugins.
|
||||
|
||||
## Writing TypeScript
|
||||
|
||||
Core, themes and plugins can be authored directly in TypeScript. Use a `.ts` extension for plain modules, or `.gts` for Glimmer components with a `<template>` tag. Type syntax is stripped at build time, so no separate compilation step is required. Linting (`@discourse/lint-configs`) and type-checking (`pnpm lint:types`) both understand these files.
|
||||
|
||||
## Usage
|
||||
|
||||
- **CLI**: Run `pnpm lint:types`
|
||||
@@ -43,25 +47,14 @@ Then run `pnpm install` and start the type watcher with `pnpm types:watch`.
|
||||
|
||||
## Enable checking for a file
|
||||
|
||||
To enable type-checking for a specific file, add `/** @ts-check */` at the top. For some examples, search Discourse core for `@ts-check`.
|
||||
`.ts` and `.gts` files are always type-checked. For `.js` / `.gjs` files, type-checking is opt-in: add `/** @ts-check */` at the top. For some examples, search Discourse core for `@ts-check`.
|
||||
|
||||
## Limitations
|
||||
|
||||
Discourse's build pipelines do not currently support `.ts` files. Types are built & checked using `.js` / `.gjs` files only.
|
||||
|
||||
We do not provide any guarantees about the accuracy of the types - they're provided on a best-effort basis. PRs to improve the JSDoc-based documentation in core are welcome.
|
||||
We do not provide any guarantees about the accuracy of the types - they're provided on a best-effort basis. PRs to improve the type documentation in core are welcome.
|
||||
|
||||
## Known Issues
|
||||
|
||||
- When importing one gjs file from another, CLI checks will report "Cannot find module". This happens due to a bug in `glint`, which requires the `.gjs` file extension to be added to the type import. The problem can be worked-around by adding a type import alongside the regular extensionless import.
|
||||
|
||||
```js
|
||||
/** @type {import("./slot.gjs").default} */
|
||||
import Slot from "./slot";
|
||||
```
|
||||
|
||||
Upstream issue [here](https://github.com/typed-ember/glint/issues/1021).
|
||||
|
||||
- Autocomplete inside `<template>` tags requires complete syntax. For example, if you start typing:
|
||||
|
||||
```
|
||||
|
||||
+4
-2
@@ -17,12 +17,14 @@ export default [
|
||||
"**/node_modules/",
|
||||
"spec/",
|
||||
"frontend/discourse/dist/",
|
||||
"frontend/discourse-types/dts-generator.js",
|
||||
"**/*.d.ts",
|
||||
"frontend/discourse-types/external-types",
|
||||
"frontend/discourse-types/dts-generator.{js,ts}",
|
||||
"tmp/",
|
||||
],
|
||||
},
|
||||
{
|
||||
files: ["themes/**/*.{js,gjs}"],
|
||||
files: ["themes/**/*.{js,gjs,ts,gts}"],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
settings: "readonly",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import BabelTransformTypescript from "@babel/plugin-transform-typescript";
|
||||
import BabelPresetEnv from "@babel/preset-env";
|
||||
import { rollup } from "@rollup/browser";
|
||||
import { babel, getBabelOutputPlugin } from "@rollup/plugin-babel";
|
||||
@@ -70,11 +71,17 @@ async function performRollup(modules, opts) {
|
||||
compact: false,
|
||||
}),
|
||||
babel({
|
||||
extensions: [".js", ".gjs", ".hbs"],
|
||||
extensions: [".js", ".gjs", ".ts", ".gts", ".hbs"],
|
||||
babelHelpers: "bundled",
|
||||
compact: false,
|
||||
// Support `import ... with { ... }` for cross-plugin imports
|
||||
parserOpts: { plugins: ["importAttributes"] },
|
||||
overrides: [
|
||||
{
|
||||
test: /\.(gts|ts|mts|cts)$/,
|
||||
plugins: [[BabelTransformTypescript, { allowDeclareFields: true }]],
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
[DecoratorTransforms, { runEarly: true }],
|
||||
opts.themeId ? AddThemeGlobals : null,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.29.7",
|
||||
"@babel/plugin-transform-typescript": "^7.29.7",
|
||||
"@babel/preset-env": "^7.29.2",
|
||||
"@babel/standalone": "^7.29.7",
|
||||
"@csstools/postcss-light-dark-function": "^3.0.1",
|
||||
|
||||
@@ -7,7 +7,7 @@ export default function discourseFileSearch() {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const ext of ["", ".js", ".gjs", ".hbs"]) {
|
||||
for (const ext of ["", ".js", ".gjs", ".ts", ".gts", ".hbs"]) {
|
||||
const resolved = await this.resolve(`${source}${ext}`, context, {
|
||||
attributes: options.attributes,
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ export default function discourseGjs() {
|
||||
// Enforce running the gjs transform before any others like babel that expect valid JS
|
||||
order: "pre",
|
||||
handler(input, id) {
|
||||
if (!id.endsWith(".gjs")) {
|
||||
if (!id.endsWith(".gjs") && !id.endsWith(".gts")) {
|
||||
return null;
|
||||
}
|
||||
let { code, map } = preprocessor.process(input, {
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
const SUPPORTED_FILE_EXTENSIONS = [".js", ".js.es6", ".hbs", ".gjs"];
|
||||
const SUPPORTED_FILE_EXTENSIONS = [
|
||||
".js",
|
||||
".js.es6",
|
||||
".hbs",
|
||||
".gjs",
|
||||
".ts",
|
||||
".gts",
|
||||
];
|
||||
|
||||
const IS_CONNECTOR_REGEX = /(^|\/)connectors\//;
|
||||
|
||||
@@ -13,6 +20,11 @@ export default {
|
||||
|
||||
let i = 1;
|
||||
for (const moduleFilename of moduleFilenames) {
|
||||
// Type-only declaration files have no runtime module to export.
|
||||
if (moduleFilename.endsWith(".d.ts")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
!SUPPORTED_FILE_EXTENSIONS.some((ext) => moduleFilename.endsWith(ext))
|
||||
) {
|
||||
|
||||
@@ -30,7 +30,7 @@ export class I18n {
|
||||
|
||||
pluralizationRules = Cardinals;
|
||||
|
||||
translate = (scope, options) => {
|
||||
translate = (scope, options = {}) => {
|
||||
return this.verbose
|
||||
? this._verboseTranslate(scope, options)
|
||||
: this._translate(scope, options);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const rawModules = import.meta.glob("./**/*.{gjs,js}", { eager: true });
|
||||
const rawModules = import.meta.glob("./**/*.{gjs,js,ts,gts}", { eager: true });
|
||||
|
||||
const adminCompatModules = {};
|
||||
for (let [key, mod] of Object.entries(rawModules)) {
|
||||
key = key.replace(/\.(gjs|js)$/, "");
|
||||
key = key.replace(/\.(gjs|js|ts|gts)$/, "");
|
||||
adminCompatModules[key] = mod;
|
||||
}
|
||||
|
||||
|
||||
+81
-70
@@ -1,4 +1,3 @@
|
||||
// @ts-check
|
||||
import Component from "@glimmer/component";
|
||||
import { on } from "@ember/modifier";
|
||||
import { action, computed } from "@ember/object";
|
||||
@@ -12,66 +11,74 @@ import dElement from "discourse/ui-kit/helpers/d-element";
|
||||
import dIcon from "discourse/ui-kit/helpers/d-icon";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
/**
|
||||
* @typedef DButtonSignature
|
||||
*
|
||||
* @property {object} Args
|
||||
*
|
||||
* // Text
|
||||
* @property {string} [Args.title]
|
||||
* @property {string} [Args.translatedTitle]
|
||||
* @property {string} [Args.label]
|
||||
* @property {string} [Args.translatedLabel]
|
||||
*
|
||||
* // Actions / events
|
||||
* @property {function|object} [Args.action]
|
||||
* @property {any} [Args.actionParam]
|
||||
* @property {boolean} [Args.forwardEvent]
|
||||
* @property {function} [Args.onKeyDown]
|
||||
*
|
||||
* // Navigation
|
||||
* @property {string} [Args.href]
|
||||
* @property {string} [Args.route]
|
||||
* @property {object|object[]} [Args.routeModels]
|
||||
*
|
||||
* // State
|
||||
* @property {boolean} [Args.isLoading]
|
||||
* @property {boolean} [Args.disabled]
|
||||
* @property {boolean} [Args.preventFocus]
|
||||
*
|
||||
* // Display mode
|
||||
* @property {"link"} [Args.display]
|
||||
*
|
||||
* // Display / icon
|
||||
* @property {string} [Args.icon]
|
||||
* @property {boolean} [Args.ellipsis]
|
||||
* @property {string} [Args.suffixIcon]
|
||||
*
|
||||
* // Accessibility
|
||||
* @property {string} [Args.ariaLabel]
|
||||
* @property {string} [Args.translatedAriaLabel]
|
||||
* @property {boolean} [Args.ariaExpanded]
|
||||
* @property {boolean} [Args.ariaPressed]
|
||||
* @property {string} [Args.ariaControls]
|
||||
* @property {boolean} [Args.ariaHidden]
|
||||
*
|
||||
* // HTML attributes
|
||||
* @property {string} [Args.type]
|
||||
* @property {string} [Args.id]
|
||||
* @property {string} [Args.form]
|
||||
* @property {string} [Args.tabindex]
|
||||
* @property {string} [Args.class]
|
||||
*
|
||||
* // Root element type (enables ...attributes type checking)
|
||||
* @property {HTMLButtonElement} Element
|
||||
*
|
||||
* // Optional yield
|
||||
* @property {object} Blocks
|
||||
* @property {[]} Blocks.default Contents of the button
|
||||
*/
|
||||
type DButtonActionCallback = (...args: unknown[]) => void;
|
||||
|
||||
/** @extends {Component<DButtonSignature>} */
|
||||
export default class DButton extends Component {
|
||||
interface DButtonActionObject {
|
||||
value: DButtonActionCallback;
|
||||
}
|
||||
|
||||
type DButtonAction = DButtonActionCallback | DButtonActionObject;
|
||||
|
||||
type RouteModel = string | number | object;
|
||||
|
||||
interface DButtonSignature {
|
||||
Args: {
|
||||
// Text
|
||||
title?: string;
|
||||
translatedTitle?: string;
|
||||
label?: string;
|
||||
translatedLabel?: string;
|
||||
|
||||
// Actions / events
|
||||
action?: DButtonAction;
|
||||
actionParam?: unknown;
|
||||
forwardEvent?: boolean;
|
||||
onKeyDown?: (event: KeyboardEvent) => void;
|
||||
|
||||
// Navigation
|
||||
href?: string;
|
||||
route?: string;
|
||||
routeModels?: RouteModel | RouteModel[];
|
||||
|
||||
// State
|
||||
isLoading?: boolean;
|
||||
disabled?: boolean;
|
||||
preventFocus?: boolean;
|
||||
|
||||
// Display mode
|
||||
display?: "link";
|
||||
|
||||
// Display / icon
|
||||
icon?: string;
|
||||
ellipsis?: boolean;
|
||||
suffixIcon?: string;
|
||||
|
||||
// Accessibility
|
||||
ariaLabel?: string;
|
||||
translatedAriaLabel?: string;
|
||||
ariaExpanded?: boolean;
|
||||
ariaPressed?: boolean;
|
||||
ariaControls?: string;
|
||||
ariaHidden?: boolean;
|
||||
|
||||
// HTML attributes
|
||||
type?: string;
|
||||
id?: string;
|
||||
form?: string;
|
||||
tabindex?: string;
|
||||
class?: string;
|
||||
};
|
||||
|
||||
// Root element type (enables ...attributes type checking)
|
||||
Element: HTMLButtonElement;
|
||||
|
||||
// Optional yield
|
||||
Blocks: {
|
||||
default: [];
|
||||
};
|
||||
}
|
||||
|
||||
export default class DButton extends Component<DButtonSignature> {
|
||||
@service router;
|
||||
@service capabilities;
|
||||
|
||||
@@ -146,7 +153,7 @@ export default class DButton extends Component {
|
||||
}
|
||||
|
||||
@action
|
||||
keyDown(e) {
|
||||
keyDown(e: KeyboardEvent) {
|
||||
if (this.args.onKeyDown) {
|
||||
e.stopPropagation();
|
||||
this.args.onKeyDown(e);
|
||||
@@ -156,18 +163,18 @@ export default class DButton extends Component {
|
||||
}
|
||||
|
||||
@action
|
||||
click(event) {
|
||||
click(event: MouseEvent) {
|
||||
return this._triggerAction(event);
|
||||
}
|
||||
|
||||
@action
|
||||
mouseDown(event) {
|
||||
mouseDown(event: MouseEvent) {
|
||||
if (this.args.preventFocus) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
_triggerAction(event) {
|
||||
_triggerAction(event: Event) {
|
||||
const { action: actionVal, route, routeModels } = this.args;
|
||||
const isIOS = this.capabilities?.isIOS;
|
||||
|
||||
@@ -179,9 +186,11 @@ export default class DButton extends Component {
|
||||
if (isIOS) {
|
||||
// Don't optimise INP in iOS
|
||||
// it results in focus events not being triggered
|
||||
forwardEvent
|
||||
? actionVal.value(actionParam, event)
|
||||
: actionVal.value(actionParam);
|
||||
if (forwardEvent) {
|
||||
actionVal.value(actionParam, event);
|
||||
} else {
|
||||
actionVal.value(actionParam);
|
||||
}
|
||||
} else {
|
||||
// Using `next()` to optimise INP
|
||||
next(() =>
|
||||
@@ -194,9 +203,11 @@ export default class DButton extends Component {
|
||||
if (isIOS) {
|
||||
// Don't optimise INP in iOS
|
||||
// it results in focus events not being triggered
|
||||
forwardEvent
|
||||
? actionVal(actionParam, event)
|
||||
: actionVal(actionParam);
|
||||
if (forwardEvent) {
|
||||
actionVal(actionParam, event);
|
||||
} else {
|
||||
actionVal(actionParam);
|
||||
}
|
||||
} else {
|
||||
// Using `next()` to optimise INP
|
||||
next(() =>
|
||||
@@ -70,6 +70,18 @@ module.exports = {
|
||||
...macros.babelMacros,
|
||||
],
|
||||
|
||||
overrides: [
|
||||
{
|
||||
test: /\.(gts|ts|mts|cts)$/,
|
||||
plugins: [
|
||||
[
|
||||
require.resolve("@babel/plugin-transform-typescript"),
|
||||
{ allowDeclareFields: true },
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
generatorOpts: {
|
||||
compact: false,
|
||||
},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const rawModules = import.meta.glob("./**/*.{gjs,js}", { eager: true });
|
||||
const rawModules = import.meta.glob("./**/*.{gjs,js,ts,gts}", { eager: true });
|
||||
|
||||
const compatModules = {};
|
||||
for (let [key, mod] of Object.entries(rawModules)) {
|
||||
key = key.replace(/\.(gjs|js)$/, "");
|
||||
key = key.replace(/\.(gjs|js|ts|gts)$/, "");
|
||||
compatModules[key] = mod;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const rawModules = import.meta.glob("./**/*.{gjs,js}", { eager: true });
|
||||
const rawModules = import.meta.glob("./**/*.{gjs,js,ts,gts}", { eager: true });
|
||||
|
||||
const compatModules = {};
|
||||
for (let [key, mod] of Object.entries(rawModules)) {
|
||||
key = key.replace(/\.(gjs|js)$/, "");
|
||||
key = key.replace(/\.(gjs|js|ts|gts)$/, "");
|
||||
compatModules[key] = mod;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const TEST_FILE_RE = /tests\/(?!helpers\/).*-test\.(?:gjs|js)$/;
|
||||
const TEST_FILE_RE = /tests\/(?!helpers\/).*-test\.(?:gjs|js|ts|gts)$/;
|
||||
|
||||
export default function wrapTestModulesPlugin() {
|
||||
return {
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.29.7",
|
||||
"@babel/plugin-transform-runtime": "^7.29.7",
|
||||
"@babel/plugin-transform-typescript": "^7.29.7",
|
||||
"@babel/standalone": "^7.29.7",
|
||||
"@colors/colors": "^1.6.0",
|
||||
"@discourse/itsatrap": "^2.0.10",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const rawModules = import.meta.glob("./**/*.{gjs,js}", { eager: true });
|
||||
const rawModules = import.meta.glob("./**/*.{gjs,js,ts,gts}", { eager: true });
|
||||
|
||||
const compatModules = {};
|
||||
for (let [key, mod] of Object.entries(rawModules)) {
|
||||
key = key.replace(/\.(gjs|js)$/, "");
|
||||
key = key.replace(/\.(gjs|js|ts|gts)$/, "");
|
||||
compatModules[key] = mod;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,9 +88,12 @@ export function pretenderHelpers() {
|
||||
}
|
||||
|
||||
export function applyDefaultHandlers() {
|
||||
const pretenderModules = import.meta.glob("./**/*-pretender.{js,gjs}", {
|
||||
eager: true,
|
||||
});
|
||||
const pretenderModules = import.meta.glob(
|
||||
"./**/*-pretender.{js,gjs,ts,gts}",
|
||||
{
|
||||
eager: true,
|
||||
}
|
||||
);
|
||||
|
||||
Object.keys(requirejs.entries).forEach((entry) => {
|
||||
if (/^discourse\/plugins\/.*helpers\/[a-z-]+\-pretender$/.test(entry)) {
|
||||
|
||||
@@ -9,13 +9,16 @@ loaderShim("ember-qunit", () => importSync("ember-qunit"));
|
||||
loaderShim("@faker-js/faker", () => importSync("@faker-js/faker"));
|
||||
loaderShim("@ember/test-helpers", () => importSync("@ember/test-helpers"));
|
||||
|
||||
const rawModules = import.meta.glob("./{fixtures,helpers}/**/*.{gjs,js}", {
|
||||
eager: true,
|
||||
});
|
||||
const rawModules = import.meta.glob(
|
||||
"./{fixtures,helpers}/**/*.{gjs,js,ts,gts}",
|
||||
{
|
||||
eager: true,
|
||||
}
|
||||
);
|
||||
|
||||
const compatModules = {};
|
||||
for (let [key, mod] of Object.entries(rawModules)) {
|
||||
key = key.replace(/\.(gjs|js)$/, "");
|
||||
key = key.replace(/\.(gjs|js|ts|gts)$/, "");
|
||||
compatModules[key] = mod;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ export async function startTests() {
|
||||
|
||||
let availableModules;
|
||||
if (testingCore) {
|
||||
const rawModules = import.meta.glob("./**/*-test.{gjs,js}", {
|
||||
const rawModules = import.meta.glob("./**/*-test.{gjs,js,ts,gts}", {
|
||||
eager: true,
|
||||
});
|
||||
availableModules = {};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const rawModules = import.meta.glob("./**/*.{gjs,js}", { eager: true });
|
||||
const rawModules = import.meta.glob("./**/*.{gjs,js,ts,gts}", { eager: true });
|
||||
|
||||
const compatModules = {};
|
||||
for (let [key, mod] of Object.entries(rawModules)) {
|
||||
key = key.replace(/\.(gjs|js)$/, "");
|
||||
key = key.replace(/\.(gjs|js|ts|gts)$/, "");
|
||||
compatModules[key] = mod;
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -31,15 +31,15 @@ pre-commit:
|
||||
prettier:
|
||||
glob: &prettier_glob
|
||||
- "app/assets/stylesheets/**/*.{css,scss}"
|
||||
- "frontend/**/*.{js,gjs,scss,css,cjs,mjs}"
|
||||
- "plugins/**/*.{js,gjs,scss,css,cjs,mjs}"
|
||||
- "themes/**/*.{js,gjs,scss,css,cjs,mjs}"
|
||||
- "frontend/**/*.{js,gjs,ts,gts,mts,cts,scss,css,cjs,mjs}"
|
||||
- "plugins/**/*.{js,gjs,ts,gts,mts,cts,scss,css,cjs,mjs}"
|
||||
- "themes/**/*.{js,gjs,ts,gts,mts,cts,scss,css,cjs,mjs}"
|
||||
run: pnpm pprettier --list-different {staged_files}
|
||||
eslint:
|
||||
glob: &eslint_glob
|
||||
- "frontend/**/*.{js,gjs}"
|
||||
- "plugins/**/*.{js,gjs}"
|
||||
- "themes/**/*.{js,gjs}"
|
||||
- "frontend/**/*.{js,gjs,ts,gts,mts,cts}"
|
||||
- "plugins/**/*.{js,gjs,ts,gts,mts,cts}"
|
||||
- "themes/**/*.{js,gjs,ts,gts,mts,cts}"
|
||||
run: pnpm eslint --max-warnings 0 {staged_files}
|
||||
yaml-syntax:
|
||||
glob: &yaml_glob "**/*.{yaml,yml}"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AssetProcessor
|
||||
BASE_COMPILER_VERSION = 112
|
||||
BASE_COMPILER_VERSION = 113
|
||||
|
||||
PROCESSOR_DIR = "tmp/asset-processor"
|
||||
LOCK_FILE = "#{PROCESSOR_DIR}/build.lock"
|
||||
|
||||
@@ -794,10 +794,12 @@ class Plugin::Instance
|
||||
Any hbs files under `assets/javascripts` will be automatically compiled and included."
|
||||
ERROR
|
||||
|
||||
raise <<~ERROR if file.start_with?("javascripts/") && file.end_with?(".js", ".js.es6")
|
||||
if file.start_with?("javascripts/") && file.end_with?(".js", ".js.es6", ".ts", ".gts")
|
||||
raise <<~ERROR
|
||||
[#{name}] Javascript files under `assets/javascripts` are automatically included in JS bundles.
|
||||
Manual register_asset calls should be removed. (attempted to add #{file})
|
||||
ERROR
|
||||
end
|
||||
|
||||
if opts && opts == :vendored_core_pretty_text
|
||||
full_path = DiscoursePluginRegistry.core_asset_for_name(file)
|
||||
|
||||
@@ -107,7 +107,7 @@ module Plugin
|
||||
)
|
||||
tree[normalized_file_path] = content
|
||||
if name == "test" && file.match(%r{/(acceptance|integration|unit)/})
|
||||
if file.match?(/-test\.g?js$/)
|
||||
if file.match?(/-test\.g?[jt]s$/)
|
||||
entrypoints_config[name][:modules] << normalized_file_path
|
||||
end
|
||||
else
|
||||
@@ -189,7 +189,7 @@ module Plugin
|
||||
listener =
|
||||
Listen.to(
|
||||
*Discourse.plugins.map(&:directory),
|
||||
{ ignore: [%r{/node_modules/}], only: /\.(gjs|js|hbs)\z/ },
|
||||
{ ignore: [%r{/node_modules/}], only: /\.(gjs|js|hbs|ts|gts)\z/ },
|
||||
) do |modified, added, removed|
|
||||
changed_files = modified + added + removed
|
||||
changed_plugins = Set.new
|
||||
@@ -245,8 +245,9 @@ module Plugin
|
||||
end
|
||||
|
||||
private_class_method def self.has_source_files_in_dir(plugin_directory_name, dir)
|
||||
Dir.glob("plugins/#{plugin_directory_name}/#{dir}/**/*.{js,hbs,gjs,es6}") { break true } ||
|
||||
false
|
||||
Dir.glob("plugins/#{plugin_directory_name}/#{dir}/**/*.{js,hbs,gjs,es6,ts,gts}") do
|
||||
break true
|
||||
end || false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -501,7 +501,7 @@ task "themes:qunit_all_official" => :environment do |task, args|
|
||||
ThemeMetadata::OFFICIAL_THEMES.each do |theme_name|
|
||||
path = Rails.root.join("tmp/themes/#{theme_name}").to_s
|
||||
|
||||
if Dir.glob("#{File.join(path, "test")}/**/*.{js,gjs}").any?
|
||||
if Dir.glob("#{File.join(path, "test")}/**/*.{js,gjs,ts,gts}").any?
|
||||
theme = RemoteTheme.import_theme_from_directory(path)
|
||||
official_theme_ids_with_qunit_tests << theme.id
|
||||
else
|
||||
@@ -514,7 +514,7 @@ task "themes:qunit_all_official" => :environment do |task, args|
|
||||
Theme::CORE_THEMES.each do |(theme_name, theme_id)|
|
||||
path = Rails.root.join("themes/#{theme_name}").to_s
|
||||
|
||||
if Dir.glob("#{File.join(path, "test")}/**/*.{js,gjs}").any?
|
||||
if Dir.glob("#{File.join(path, "test")}/**/*.{js,gjs,ts,gts}").any?
|
||||
core_theme_ids_with_qunit_tests << theme_id
|
||||
else
|
||||
puts "Skipping #{theme_name} as no QUnit tests have been detected"
|
||||
|
||||
+3
-3
@@ -4,7 +4,7 @@
|
||||
"author": "Discourse",
|
||||
"license": "GPL-2.0-only",
|
||||
"devDependencies": {
|
||||
"@discourse/lint-configs": "^3.1.2",
|
||||
"@discourse/lint-configs": "^3.2.0",
|
||||
"@discourse/moment-timezone-names-translations": "^1.0.0",
|
||||
"@fortawesome/fontawesome-free": "7.2.0",
|
||||
"@glint/ember-tsc": "^1.8.11",
|
||||
@@ -31,8 +31,8 @@
|
||||
"lint:css:fix": "pnpm stylelint --fix 'app/assets/stylesheets/**/*.scss' $(script/list_bundled_plugins '/assets/stylesheets/**/*.scss') 'themes/**/*.scss'",
|
||||
"lint:js": "eslint ./frontend $(script/list_bundled_plugins) ./themes --cache --no-error-on-unmatched-pattern --max-warnings 0",
|
||||
"lint:js:fix": "eslint --fix ./frontend $(script/list_bundled_plugins) ./themes --no-error-on-unmatched-pattern",
|
||||
"lint:prettier": "pnpm pprettier --list-different 'app/assets/stylesheets/**/*.scss' 'frontend/**/*.{js,gjs,css}' $(script/list_bundled_plugins '/assets/stylesheets/**/*.scss') $(script/list_bundled_plugins '/{assets,admin/assets,test}/javascripts/**/*.{js,gjs}') 'themes/**/*.{js,gjs,scss}'",
|
||||
"lint:prettier:fix": "pnpm prettier -w --no-error-on-unmatched-pattern 'app/assets/stylesheets/**/*.scss' 'frontend/**/*.{js,gjs,css}' $(script/list_bundled_plugins '/assets/stylesheets/**/*.scss') $(script/list_bundled_plugins '/{assets,admin/assets,test}/javascripts/**/*.{js,gjs}') 'themes/**/*.{js,gjs,scss}'",
|
||||
"lint:prettier": "pnpm pprettier --list-different 'app/assets/stylesheets/**/*.scss' 'frontend/**/*.{js,gjs,ts,gts,mts,cts,css}' $(script/list_bundled_plugins '/assets/stylesheets/**/*.scss') $(script/list_bundled_plugins '/{assets,admin/assets,test}/javascripts/**/*.{js,gjs,ts,gts,mts,cts}') 'themes/**/*.{js,gjs,ts,gts,scss}'",
|
||||
"lint:prettier:fix": "pnpm prettier -w --no-error-on-unmatched-pattern 'app/assets/stylesheets/**/*.scss' 'frontend/**/*.{js,gjs,ts,gts,mts,cts,css}' $(script/list_bundled_plugins '/assets/stylesheets/**/*.scss') $(script/list_bundled_plugins '/{assets,admin/assets,test}/javascripts/**/*.{js,gjs,ts,gts,mts,cts}') 'themes/**/*.{js,gjs,ts,gts,scss}'",
|
||||
"lint:types": "ember-tsc -b",
|
||||
"types:generate": "pnpm --dir=frontend/discourse-i18n ember-tsc && pnpm --dir=frontend/discourse-types generate-external",
|
||||
"types:watch": "pnpm types:generate && pnpm ember-tsc -b --watch --preserveWatchOutput",
|
||||
|
||||
+8
-2
@@ -1,6 +1,9 @@
|
||||
const BOTTOM_VISIBILITY_SLACK = 10;
|
||||
|
||||
export function checkMessageBottomVisibility(list, message) {
|
||||
export function checkMessageBottomVisibility(
|
||||
list: Element,
|
||||
message: Element
|
||||
): boolean {
|
||||
const distanceToTop = window.pageYOffset + list.getBoundingClientRect().top;
|
||||
const bounding = message.getBoundingClientRect();
|
||||
return (
|
||||
@@ -9,7 +12,10 @@ export function checkMessageBottomVisibility(list, message) {
|
||||
);
|
||||
}
|
||||
|
||||
export function checkMessageTopVisibility(list, message) {
|
||||
export function checkMessageTopVisibility(
|
||||
list: Element,
|
||||
message: Element
|
||||
): boolean {
|
||||
const distanceToTop = window.pageYOffset + list.getBoundingClientRect().top;
|
||||
const bounding = message.getBoundingClientRect();
|
||||
return bounding.top - distanceToTop >= -1;
|
||||
Generated
+248
-34
@@ -46,8 +46,8 @@ importers:
|
||||
.:
|
||||
devDependencies:
|
||||
'@discourse/lint-configs':
|
||||
specifier: ^3.1.2
|
||||
version: 3.1.2(jiti@2.6.1)(postcss@8.5.15)(prettier@3.8.1)
|
||||
specifier: ^3.2.0
|
||||
version: 3.2.0(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.6.0(jiti@2.6.1))(postcss@8.5.15)(prettier@3.8.1)(stylelint@17.5.0(typescript@5.9.3))
|
||||
'@discourse/moment-timezone-names-translations':
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
@@ -104,7 +104,7 @@ importers:
|
||||
devDependencies:
|
||||
'@discourse/lint-configs':
|
||||
specifier: ^3.1.2
|
||||
version: 3.1.2(jiti@2.6.1)(postcss@8.5.15)(prettier@3.8.1)
|
||||
version: 3.2.0(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.6.0(jiti@2.6.1))(postcss@8.5.15)(prettier@3.8.1)(stylelint@17.5.0(typescript@5.9.3))
|
||||
prettier:
|
||||
specifier: 3.8.1
|
||||
version: 3.8.1
|
||||
@@ -114,6 +114,9 @@ importers:
|
||||
'@babel/core':
|
||||
specifier: ^7.29.7
|
||||
version: 7.29.7
|
||||
'@babel/plugin-transform-typescript':
|
||||
specifier: ^7.29.7
|
||||
version: 7.29.7(@babel/core@7.29.7)
|
||||
'@babel/preset-env':
|
||||
specifier: ^7.29.2
|
||||
version: 7.29.7(@babel/core@7.29.7)
|
||||
@@ -433,6 +436,9 @@ importers:
|
||||
'@babel/plugin-transform-runtime':
|
||||
specifier: ^7.29.7
|
||||
version: 7.29.7(@babel/core@7.29.7)
|
||||
'@babel/plugin-transform-typescript':
|
||||
specifier: ^7.29.7
|
||||
version: 7.29.7(@babel/core@7.29.7)
|
||||
'@babel/standalone':
|
||||
specifier: ^7.29.7
|
||||
version: 7.29.7
|
||||
@@ -1779,10 +1785,12 @@ packages:
|
||||
'@discourse/jxl@1.3.0':
|
||||
resolution: {integrity: sha512-Veu75DEDC7uKsCCsD94UIjFwvHE73+AATBQbBWb83QyJV34wmyxl2Ji+fiiM234mlNn4cpo3DUl0QFrXgRTcfA==}
|
||||
|
||||
'@discourse/lint-configs@3.1.2':
|
||||
resolution: {integrity: sha512-XDioMsCXakfYrsXzMdM1CfYKXUImt7hlfDUmfkprd8gMo4E9VRsbDxS3ITo3rZL9toNUrFsquYfMcxx5/QVzPg==}
|
||||
'@discourse/lint-configs@3.2.0':
|
||||
resolution: {integrity: sha512-mEZYPNlGyf+Jq6i6QKzi2mXw9ofgcEh1XARoQKQS1Y+SsclJgGHT33MUxn5QwWEaGpSYA67/0hdPVL+HEW29gw==}
|
||||
peerDependencies:
|
||||
eslint: 10.6.0
|
||||
prettier: 3.8.1
|
||||
stylelint: 17.5.0
|
||||
|
||||
'@discourse/moment-timezone-names-translations@1.0.0':
|
||||
resolution: {integrity: sha512-4xr1QWQ0nzmFa2ZXQgWZA+dtE/BU2ePA+qkJWPFzNpq4ZnQi8MmMMAS2285t3rc2ySMBQqYaAArmcSUiufUgRA==}
|
||||
@@ -2347,6 +2355,12 @@ packages:
|
||||
'@emnapi/core': ^1.7.1
|
||||
'@emnapi/runtime': ^1.7.1
|
||||
|
||||
'@napi-rs/wasm-runtime@1.1.6':
|
||||
resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==}
|
||||
peerDependencies:
|
||||
'@emnapi/core': ^1.7.1
|
||||
'@emnapi/runtime': ^1.7.1
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -2842,6 +2856,9 @@ packages:
|
||||
'@tybys/wasm-util@0.10.2':
|
||||
resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==}
|
||||
|
||||
'@tybys/wasm-util@0.10.3':
|
||||
resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==}
|
||||
|
||||
'@types/babel__code-frame@7.27.0':
|
||||
resolution: {integrity: sha512-Dwlo+LrxDx/0SpfmJ/BKveHf7QXWvLBLc+x03l5sbzykj3oB9nHygCpSECF1a+s+QIxbghe+KHqC90vGtxLRAA==}
|
||||
|
||||
@@ -2924,12 +2941,71 @@ packages:
|
||||
'@types/ws@8.18.1':
|
||||
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.59.3':
|
||||
resolution: {integrity: sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==}
|
||||
'@typescript-eslint/eslint-plugin@8.62.1':
|
||||
resolution: {integrity: sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^8.62.1
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/parser@8.62.1':
|
||||
resolution: {integrity: sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/project-service@8.62.1':
|
||||
resolution: {integrity: sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/scope-manager@8.62.1':
|
||||
resolution: {integrity: sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.62.1':
|
||||
resolution: {integrity: sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.63.0':
|
||||
resolution: {integrity: sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/type-utils@8.62.1':
|
||||
resolution: {integrity: sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/types@8.62.1':
|
||||
resolution: {integrity: sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.62.1':
|
||||
resolution: {integrity: sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/utils@8.62.1':
|
||||
resolution: {integrity: sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.62.1':
|
||||
resolution: {integrity: sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@uppy/aws-s3@5.1.0':
|
||||
resolution: {integrity: sha512-UBz+shrtDbnOf11AboDrkc9Fq2Cdf8HbFftE+gqfxig6fkv5rHpHhBCLkl8wCGAq+X/CxdqvvNhm/OM23Uzw2w==}
|
||||
peerDependencies:
|
||||
@@ -4253,8 +4329,8 @@ packages:
|
||||
ember-curry-component@0.4.0:
|
||||
resolution: {integrity: sha512-mXtlgCA0eW5B4ZdIP4qqMeatFCxKni7uuLbo06UK1a9y/itL5nKQosHwbyx5N7TfXXQt8oQl0oXAliIvw2sdmA==}
|
||||
|
||||
ember-eslint-parser@0.14.0:
|
||||
resolution: {integrity: sha512-lFF19I8DhsAdNfUIV5ljC+2lHVUp1So1iQE1/ZbhMwHCq/c1s2G2XnUtal/DxLM/L+ZCwU0VTf2hwDqvqCxkZw==}
|
||||
ember-eslint-parser@0.14.3:
|
||||
resolution: {integrity: sha512-jU1HtVHqlbzqRDMwS4lxggjIY7u/wr+lij4bEvyC1CpNd5YqHK7anK3ubmVZLiB19VrFO6tH2/iYUQ+drpSYuA==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
peerDependencies:
|
||||
'@babel/eslint-parser': ^7.28.6 || ^8.0.0
|
||||
@@ -4265,8 +4341,8 @@ packages:
|
||||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
|
||||
ember-estree@0.6.4:
|
||||
resolution: {integrity: sha512-/0+JLFt200RB/gUfLfRALTFWby6fGS7Bu+NN985Y8gadEntX4KoiYHhOl2hkzvy+AmBi+PbHxBa9QVCV7K/PUg==}
|
||||
ember-estree@0.6.10:
|
||||
resolution: {integrity: sha512-5nItZGzvxHgoCdASQbn9qBzF4sdjSggUeZpXdihAanmYWm6XkObT/TlUvakYtoKret1/8gm0jNLwNPqZYwHtCw==}
|
||||
|
||||
ember-exam@10.1.0:
|
||||
resolution: {integrity: sha512-6jUftmu2zpmLZ35PCsZDbdsAXTm2GjCGT3SjRX+BkUr2yKYpbD9B2R7hqCUnqOOTkdp2lzhBcGZ+KwwLLdH7eg==}
|
||||
@@ -4460,8 +4536,8 @@ packages:
|
||||
'@babel/eslint-parser':
|
||||
optional: true
|
||||
|
||||
eslint-plugin-ember@13.4.0:
|
||||
resolution: {integrity: sha512-D7fDHqTEFPMw8bnvMLGmLsLqenUj0/cCKrg7/WTB4dv+MaSS6JjR4TYycOE9n5jKbIgOlmXA2zMUDya7sVkl0Q==}
|
||||
eslint-plugin-ember@13.4.1:
|
||||
resolution: {integrity: sha512-KyPKk3SfYQ5ci9U/bvVIA0NFB1UFn6rZAHNNb62AOgcMUNIR1/+0zqzyhrLHPyodo8BmE+kKDj7subsp71NkqA==}
|
||||
engines: {node: '>= 20.19'}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': '*'
|
||||
@@ -7478,8 +7554,8 @@ packages:
|
||||
styled_string@0.0.1:
|
||||
resolution: {integrity: sha512-DU2KZiB6VbPkO2tGSqQ9n96ZstUPjW7X4sGO6V2m1myIQluX0p1Ol8BrA/l6/EesqhMqXOIXs3cJNOy1UuU2BA==}
|
||||
|
||||
stylelint-config-recommended-scss@17.0.0:
|
||||
resolution: {integrity: sha512-VkVD9r7jfUT/dq3mA3/I1WXXk2U71rO5wvU2yIil9PW5o1g3UM7Xc82vHmuVJHV7Y8ok5K137fmW5u3HbhtTOA==}
|
||||
stylelint-config-recommended-scss@17.0.1:
|
||||
resolution: {integrity: sha512-x5DVehzJudcwF0od3sGpgkln2PLLranFE7twwbp7dqDINCyZvwzFkMc6TLhNOvazRiVBJYATQLouJY0xPGB8WA==}
|
||||
engines: {node: '>=20'}
|
||||
peerDependencies:
|
||||
postcss: ^8.3.3
|
||||
@@ -7510,8 +7586,8 @@ packages:
|
||||
peerDependencies:
|
||||
stylelint: ^17.0.0
|
||||
|
||||
stylelint-scss@7.0.0:
|
||||
resolution: {integrity: sha512-H88kCC+6Vtzj76NsC8rv6x/LW8slBzIbyeSjsKVlS+4qaEJoDrcJR4L+8JdrR2ORdTscrBzYWiiT2jq6leYR1Q==}
|
||||
stylelint-scss@7.2.0:
|
||||
resolution: {integrity: sha512-6E79Bachv0Iz0gqRUZgdqdXCsiq26DWBWIBNHYtjTmAp3wJu6cp/I37VfW7BPntmh2puF3bY09XWl4HZGrLhzw==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
peerDependencies:
|
||||
stylelint: ^16.8.2 || ^17.0.0
|
||||
@@ -7710,6 +7786,12 @@ packages:
|
||||
resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==}
|
||||
engines: {node: '>= 14.0.0'}
|
||||
|
||||
ts-api-utils@2.5.0:
|
||||
resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==}
|
||||
engines: {node: '>=18.12'}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4'
|
||||
|
||||
tslib@1.14.1:
|
||||
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
|
||||
|
||||
@@ -7762,6 +7844,13 @@ packages:
|
||||
typescript-auto-import-cache@0.3.6:
|
||||
resolution: {integrity: sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==}
|
||||
|
||||
typescript-eslint@8.62.1:
|
||||
resolution: {integrity: sha512-vymnnM5g0AKQDSAyfP12nMIBvgwgA42syg74kkuZ4x1VuTzwQKwc5h9rGxeShCjny5o+zWAb6OEoz7XLgrIkIw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
typescript-memoize@1.1.1:
|
||||
resolution: {integrity: sha512-GQ90TcKpIH4XxYTI2F98yEQYZgjNMOGPpOgdjIBhaLaWji5HPWlRnZ4AeA1hfBxtY7bCGDJsqDDHk/KaHOl5bA==}
|
||||
|
||||
@@ -9327,15 +9416,16 @@ snapshots:
|
||||
dependencies:
|
||||
wasm-feature-detect: 1.8.0
|
||||
|
||||
'@discourse/lint-configs@3.1.2(jiti@2.6.1)(postcss@8.5.15)(prettier@3.8.1)':
|
||||
'@discourse/lint-configs@3.2.0(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.6.0(jiti@2.6.1))(postcss@8.5.15)(prettier@3.8.1)(stylelint@17.5.0(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@babel/core': 8.0.1
|
||||
'@babel/eslint-parser': 8.0.1(@babel/core@8.0.1)(eslint@10.6.0(jiti@2.6.1))
|
||||
'@babel/plugin-proposal-decorators': 8.0.2(@babel/core@8.0.1)
|
||||
'@eslint/js': 10.0.1(eslint@10.6.0(jiti@2.6.1))
|
||||
ember-eslint-parser: 0.14.3(@babel/eslint-parser@8.0.1(@babel/core@8.0.1)(eslint@10.6.0(jiti@2.6.1)))(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3))(typescript@5.9.3)
|
||||
eslint: 10.6.0(jiti@2.6.1)
|
||||
eslint-plugin-decorator-position: 6.1.1(@babel/eslint-parser@8.0.1(@babel/core@8.0.1)(eslint@10.6.0(jiti@2.6.1)))(eslint@10.6.0(jiti@2.6.1))
|
||||
eslint-plugin-ember: 13.4.0(@babel/eslint-parser@8.0.1(@babel/core@8.0.1)(eslint@10.6.0(jiti@2.6.1)))(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
eslint-plugin-ember: 13.4.1(@babel/eslint-parser@8.0.1(@babel/core@8.0.1)(eslint@10.6.0(jiti@2.6.1)))(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
eslint-plugin-qunit: 8.2.6(eslint@10.6.0(jiti@2.6.1))
|
||||
eslint-plugin-simple-import-sort: 13.0.0(eslint@10.6.0(jiti@2.6.1))
|
||||
eslint-plugin-sort-class-members: 1.22.1(eslint@10.6.0(jiti@2.6.1))
|
||||
@@ -9345,11 +9435,11 @@ snapshots:
|
||||
stylelint: 17.5.0(typescript@5.9.3)
|
||||
stylelint-config-standard: 40.0.0(stylelint@17.5.0(typescript@5.9.3))
|
||||
stylelint-config-standard-scss: 17.0.0(postcss@8.5.15)(stylelint@17.5.0(typescript@5.9.3))
|
||||
stylelint-scss: 7.0.0(stylelint@17.5.0(typescript@5.9.3))
|
||||
stylelint-scss: 7.2.0(stylelint@17.5.0(typescript@5.9.3))
|
||||
typescript: 5.9.3
|
||||
typescript-eslint: 8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
transitivePeerDependencies:
|
||||
- '@typescript-eslint/parser'
|
||||
- jiti
|
||||
- postcss
|
||||
- supports-color
|
||||
|
||||
@@ -10194,6 +10284,13 @@ snapshots:
|
||||
'@tybys/wasm-util': 0.10.2
|
||||
optional: true
|
||||
|
||||
'@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
|
||||
dependencies:
|
||||
'@emnapi/core': 1.10.0
|
||||
'@emnapi/runtime': 1.10.0
|
||||
'@tybys/wasm-util': 0.10.3
|
||||
optional: true
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
dependencies:
|
||||
'@nodelib/fs.stat': 2.0.5
|
||||
@@ -10390,7 +10487,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@emnapi/core': 1.10.0
|
||||
'@emnapi/runtime': 1.10.0
|
||||
'@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
|
||||
'@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-win32-arm64-msvc@0.130.0':
|
||||
@@ -10624,6 +10721,11 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@tybys/wasm-util@0.10.3':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@types/babel__code-frame@7.27.0': {}
|
||||
|
||||
'@types/chai@5.2.3':
|
||||
@@ -10701,10 +10803,101 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/node': 25.9.1
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.59.3(typescript@5.9.3)':
|
||||
'@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@typescript-eslint/parser': 8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
'@typescript-eslint/scope-manager': 8.62.1
|
||||
'@typescript-eslint/type-utils': 8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.62.1
|
||||
eslint: 10.6.0(jiti@2.6.1)
|
||||
ignore: 7.0.5
|
||||
natural-compare: 1.4.0
|
||||
ts-api-utils: 2.5.0(typescript@5.9.3)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.62.1
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/typescript-estree': 8.62.1(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.62.1
|
||||
debug: 4.4.3
|
||||
eslint: 10.6.0(jiti@2.6.1)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/project-service@8.62.1(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/tsconfig-utils': 8.63.0(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
debug: 4.4.3
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/scope-manager@8.62.1':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/visitor-keys': 8.62.1
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.62.1(typescript@5.9.3)':
|
||||
dependencies:
|
||||
typescript: 5.9.3
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.63.0(typescript@5.9.3)':
|
||||
dependencies:
|
||||
typescript: 5.9.3
|
||||
|
||||
'@typescript-eslint/type-utils@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/typescript-estree': 8.62.1(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
debug: 4.4.3
|
||||
eslint: 10.6.0(jiti@2.6.1)
|
||||
ts-api-utils: 2.5.0(typescript@5.9.3)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/types@8.62.1': {}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.62.1(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/project-service': 8.62.1(typescript@5.9.3)
|
||||
'@typescript-eslint/tsconfig-utils': 8.62.1(typescript@5.9.3)
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/visitor-keys': 8.62.1
|
||||
debug: 4.4.3
|
||||
minimatch: 10.2.5
|
||||
semver: 7.8.4
|
||||
tinyglobby: 0.2.17
|
||||
ts-api-utils: 2.5.0(typescript@5.9.3)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0(jiti@2.6.1))
|
||||
'@typescript-eslint/scope-manager': 8.62.1
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
'@typescript-eslint/typescript-estree': 8.62.1(typescript@5.9.3)
|
||||
eslint: 10.6.0(jiti@2.6.1)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.62.1':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.62.1
|
||||
eslint-visitor-keys: 5.0.1
|
||||
|
||||
'@uppy/aws-s3@5.1.0(@uppy/core@5.2.0)':
|
||||
dependencies:
|
||||
'@uppy/companion-client': 5.1.1(@uppy/core@5.2.0)
|
||||
@@ -12410,22 +12603,23 @@ snapshots:
|
||||
- '@babel/core'
|
||||
- supports-color
|
||||
|
||||
ember-eslint-parser@0.14.0(@babel/eslint-parser@8.0.1(@babel/core@8.0.1)(eslint@10.6.0(jiti@2.6.1)))(typescript@5.9.3):
|
||||
ember-eslint-parser@0.14.3(@babel/eslint-parser@8.0.1(@babel/core@8.0.1)(eslint@10.6.0(jiti@2.6.1)))(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3))(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@glimmer/syntax': 0.95.0
|
||||
'@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3)
|
||||
'@typescript-eslint/tsconfig-utils': 8.63.0(typescript@5.9.3)
|
||||
content-tag: 4.2.0
|
||||
ember-estree: 0.6.4
|
||||
ember-estree: 0.6.10
|
||||
eslint-scope: 9.1.2
|
||||
html-tags: 5.1.0
|
||||
mathml-tag-names: 4.0.0
|
||||
svg-tags: 1.0.0
|
||||
optionalDependencies:
|
||||
'@babel/eslint-parser': 8.0.1(@babel/core@8.0.1)(eslint@10.6.0(jiti@2.6.1))
|
||||
'@typescript-eslint/parser': 8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
ember-estree@0.6.4:
|
||||
ember-estree@0.6.10:
|
||||
dependencies:
|
||||
'@glimmer/env': 0.1.7
|
||||
'@glimmer/syntax': 0.95.0
|
||||
@@ -12790,14 +12984,14 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-ember@13.4.0(@babel/eslint-parser@8.0.1(@babel/core@8.0.1)(eslint@10.6.0(jiti@2.6.1)))(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3):
|
||||
eslint-plugin-ember@13.4.1(@babel/eslint-parser@8.0.1(@babel/core@8.0.1)(eslint@10.6.0(jiti@2.6.1)))(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@ember-data/rfc395-data': 0.0.4
|
||||
aria-query: 5.3.2
|
||||
axobject-query: 4.1.0
|
||||
css-tree: 3.2.1
|
||||
editorconfig: 3.0.2
|
||||
ember-eslint-parser: 0.14.0(@babel/eslint-parser@8.0.1(@babel/core@8.0.1)(eslint@10.6.0(jiti@2.6.1)))(typescript@5.9.3)
|
||||
ember-eslint-parser: 0.14.3(@babel/eslint-parser@8.0.1(@babel/core@8.0.1)(eslint@10.6.0(jiti@2.6.1)))(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3))(typescript@5.9.3)
|
||||
ember-rfc176-data: 0.3.18
|
||||
eslint: 10.6.0(jiti@2.6.1)
|
||||
eslint-utils: 3.0.0(eslint@10.6.0(jiti@2.6.1))
|
||||
@@ -12810,6 +13004,8 @@ snapshots:
|
||||
requireindex: 1.2.0
|
||||
snake-case: 3.0.4
|
||||
svg-tags: 1.0.0
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
transitivePeerDependencies:
|
||||
- '@babel/eslint-parser'
|
||||
- typescript
|
||||
@@ -16138,12 +16334,12 @@ snapshots:
|
||||
|
||||
styled_string@0.0.1: {}
|
||||
|
||||
stylelint-config-recommended-scss@17.0.0(postcss@8.5.15)(stylelint@17.5.0(typescript@5.9.3)):
|
||||
stylelint-config-recommended-scss@17.0.1(postcss@8.5.15)(stylelint@17.5.0(typescript@5.9.3)):
|
||||
dependencies:
|
||||
postcss-scss: 4.0.9(postcss@8.5.15)
|
||||
stylelint: 17.5.0(typescript@5.9.3)
|
||||
stylelint-config-recommended: 18.0.0(stylelint@17.5.0(typescript@5.9.3))
|
||||
stylelint-scss: 7.0.0(stylelint@17.5.0(typescript@5.9.3))
|
||||
stylelint-scss: 7.2.0(stylelint@17.5.0(typescript@5.9.3))
|
||||
optionalDependencies:
|
||||
postcss: 8.5.15
|
||||
|
||||
@@ -16154,7 +16350,7 @@ snapshots:
|
||||
stylelint-config-standard-scss@17.0.0(postcss@8.5.15)(stylelint@17.5.0(typescript@5.9.3)):
|
||||
dependencies:
|
||||
stylelint: 17.5.0(typescript@5.9.3)
|
||||
stylelint-config-recommended-scss: 17.0.0(postcss@8.5.15)(stylelint@17.5.0(typescript@5.9.3))
|
||||
stylelint-config-recommended-scss: 17.0.1(postcss@8.5.15)(stylelint@17.5.0(typescript@5.9.3))
|
||||
stylelint-config-standard: 40.0.0(stylelint@17.5.0(typescript@5.9.3))
|
||||
optionalDependencies:
|
||||
postcss: 8.5.15
|
||||
@@ -16164,12 +16360,15 @@ snapshots:
|
||||
stylelint: 17.5.0(typescript@5.9.3)
|
||||
stylelint-config-recommended: 18.0.0(stylelint@17.5.0(typescript@5.9.3))
|
||||
|
||||
stylelint-scss@7.0.0(stylelint@17.5.0(typescript@5.9.3)):
|
||||
stylelint-scss@7.2.0(stylelint@17.5.0(typescript@5.9.3)):
|
||||
dependencies:
|
||||
'@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
|
||||
'@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
|
||||
'@csstools/css-syntax-patches-for-csstree': 1.1.5(css-tree@3.2.1)
|
||||
'@csstools/css-tokenizer': 4.0.0
|
||||
css-tree: 3.2.1
|
||||
is-plain-object: 5.0.0
|
||||
known-css-properties: 0.37.0
|
||||
mdn-data: 2.27.1
|
||||
postcss-media-query-parser: 0.2.3
|
||||
postcss-resolve-nested-selector: 0.1.6
|
||||
postcss-selector-parser: 7.1.4
|
||||
@@ -16512,6 +16711,10 @@ snapshots:
|
||||
|
||||
triple-beam@1.4.1: {}
|
||||
|
||||
ts-api-utils@2.5.0(typescript@5.9.3):
|
||||
dependencies:
|
||||
typescript: 5.9.3
|
||||
|
||||
tslib@1.14.1: {}
|
||||
|
||||
tslib@2.8.1: {}
|
||||
@@ -16579,6 +16782,17 @@ snapshots:
|
||||
dependencies:
|
||||
semver: 7.8.4
|
||||
|
||||
typescript-eslint@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
'@typescript-eslint/parser': 8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
'@typescript-eslint/typescript-estree': 8.62.1(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.62.1(eslint@10.6.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
eslint: 10.6.0(jiti@2.6.1)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
typescript-memoize@1.1.1: {}
|
||||
|
||||
typescript@5.9.3: {}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe "Theme TypeScript support" do
|
||||
it "compiles and runs a theme .gts file authored in TypeScript" do
|
||||
theme = Fabricate(:theme, name: "TypeScript Theme")
|
||||
theme.set_field(
|
||||
target: :extra_js,
|
||||
type: :js,
|
||||
name: "discourse/connectors/below-footer/typescript-proof.gts",
|
||||
value: <<~GTS,
|
||||
import Component from "@glimmer/component";
|
||||
|
||||
interface Rgb {
|
||||
r: number;
|
||||
g: number;
|
||||
b: number;
|
||||
}
|
||||
|
||||
function toCss({ r, g, b }: Rgb): string {
|
||||
return `rgb(${r}, ${g}, ${b})`;
|
||||
}
|
||||
|
||||
export default class TypescriptProof extends Component {
|
||||
color: Rgb = { r: 0, g: 128, b: 0 };
|
||||
|
||||
get label(): string {
|
||||
return toCss(this.color);
|
||||
}
|
||||
|
||||
<template>
|
||||
<div class="ts-theme-proof">{{this.label}}</div>
|
||||
</template>
|
||||
}
|
||||
GTS
|
||||
)
|
||||
theme.save!
|
||||
SiteSetting.default_theme_id = theme.id
|
||||
|
||||
visit "/latest"
|
||||
|
||||
expect(page).to have_css(".ts-theme-proof", text: "rgb(0, 128, 0)")
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user