Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ember-scoped-css/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"types": "./declarations/runtime/index.d.ts",
"default": "./dist/runtime/index.js"
},
"./__private_do_not_use_are_you_serious__/style-tag": "./src/build/style-tag.js",
"./babel": {
"import": "./src/build/public-exports/babel.js",
"require": "./dist/cjs/babel.cjs"
Expand Down
77 changes: 77 additions & 0 deletions ember-scoped-css/src/build/style-tag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* How a `<style>` element in a template is read: whether the build scopes it,
* and whether its contents need a preprocessor before anything can treat them
* as CSS.
*
* Thanks, CardStack and @ef4 for this code.
*/

const SCOPED_ATTRIBUTE_NAME = 'scoped';
const INLINE_ATTRIBUTE_NAME = 'inline';
const LANG_ATTRIBUTE_NAME = 'lang';

/**
* @param {object} [node]
* @returns {boolean | undefined}
*/
export function hasScopedAttribute(node) {
if (!node) return;
if (node.tag !== 'style') return;
if (node.type !== 'ElementNode') return;

return node.attributes.some(
(attribute) => attribute.name === SCOPED_ATTRIBUTE_NAME,
);
}

/**
* @param {object} [node]
* @returns {boolean | undefined}
*/
export function hasInlineAttributeWithoutLang(node) {
if (!node) return;
if (node.tag !== 'style') return;
if (node.type !== 'ElementNode') return;

if (getLangAttribute(node)) {
return false;
}

return node.attributes.some(
(attribute) => attribute.name === INLINE_ATTRIBUTE_NAME,
);
}

/**
* Returns the value of the `lang` attribute on a `<style>` node, or null if absent.
*
* @param {object} [node]
* @returns {string | null}
*/
export function getLangAttribute(node) {
if (!node) return null;
if (node.tag !== 'style') return null;
if (node.type !== 'ElementNode') return null;

const attr = node.attributes.find(
(attribute) => attribute.name === LANG_ATTRIBUTE_NAME,
);

if (!attr) return null;

// The attribute value is a TextNode child of the AttrNode's value
const value = attr.value;

if (value?.type === 'TextNode') return value.chars || null;

return null;
}

/** File extensions that Vite can preprocess via its CSS preprocessor pipeline */
export const PREPROCESSED_EXTENSIONS = new Set([
'.scss',
'.sass',
'.less',
'.styl',
'.stylus',
]);
61 changes: 5 additions & 56 deletions ember-scoped-css/src/build/template-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ import {
} from '../lib/path/utils.js';
import { request } from '../lib/request.js';
import { templatePlugin } from '../lib/rewriteHbs.js';
import {
getLangAttribute,
hasInlineAttributeWithoutLang,
hasScopedAttribute,
} from './style-tag.js';

const noopPlugin = {
name: 'ember-scoped-css:noop',
Expand Down Expand Up @@ -236,62 +241,6 @@ export function createPlugin(config) {
};
}

/**
* Thanks, CardStack and @ef4 for this code.
*/
const SCOPED_ATTRIBUTE_NAME = 'scoped';
const INLINE_ATTRIBUTE_NAME = 'inline';
const LANG_ATTRIBUTE_NAME = 'lang';

function hasScopedAttribute(node) {
if (!node) return;
if (node.tag !== 'style') return;
if (node.type !== 'ElementNode') return;

return node.attributes.some(
(attribute) => attribute.name === SCOPED_ATTRIBUTE_NAME,
);
}

function hasInlineAttributeWithoutLang(node) {
if (!node) return;
if (node.tag !== 'style') return;
if (node.type !== 'ElementNode') return;

if (getLangAttribute(node)) {
return false;
}

return node.attributes.some(
(attribute) => attribute.name === INLINE_ATTRIBUTE_NAME,
);
}

/**
* Returns the value of the `lang` attribute on a `<style>` node, or null if absent.
*
* @param {object} node
* @returns {string | null}
*/
function getLangAttribute(node) {
if (!node) return null;
if (node.tag !== 'style') return null;
if (node.type !== 'ElementNode') return null;

const attr = node.attributes.find(
(attribute) => attribute.name === LANG_ATTRIBUTE_NAME,
);

if (!attr) return null;

// The attribute value is a TextNode child of the AttrNode's value
const value = attr.value;

if (value?.type === 'TextNode') return value.chars || null;

return null;
}

function textContent(node) {
let textChildren = node.children.filter((c) => c.type === 'TextNode');

Expand Down
10 changes: 1 addition & 9 deletions ember-scoped-css/src/build/unplugin-colocated.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,10 @@ import path from 'node:path';

import { rewriteCss } from '../lib/css/rewrite.js';
import { request } from '../lib/request.js';
import { PREPROCESSED_EXTENSIONS } from './style-tag.js';

const META = 'scoped-css:colocated';

/** File extensions that Vite can preprocess via its CSS preprocessor pipeline */
const PREPROCESSED_EXTENSIONS = new Set([
'.scss',
'.sass',
'.less',
'.styl',
'.stylus',
]);

/**
* Plugin for supporting colocated styles
*
Expand Down
Loading