@protobase/cli 0.12.5 → 0.12.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ import { uiPackageDir } from "../project/admin-app.js";
3
3
  import { extensionImports } from "../project/extensions.js";
4
4
  import { sharedModules } from "../project/shared-modules.js";
5
5
  import { pluginFieldTypes } from "./plugin-fields.js";
6
+ import { layerPluginUtilities } from "./plugin-styles.js";
6
7
  import { createRequire } from "node:module";
7
8
  import { existsSync } from "node:fs";
8
9
  import path from "node:path";
@@ -69,6 +70,13 @@ const pluginStyles = (file, code) => ({
69
70
  resolveId: (id) => id === file ? id : void 0,
70
71
  load: (id) => id === file ? code : void 0
71
72
  });
73
+ const layeredStyles = () => ({
74
+ name: "protobase-plugin-layered-styles",
75
+ enforce: "post",
76
+ generateBundle(_, bundle) {
77
+ for (const file of Object.values(bundle)) if (file.type === "asset" && file.fileName.endsWith(".css")) file.source = layerPluginUtilities(String(file.source));
78
+ }
79
+ });
72
80
  const outputOf = (result) => {
73
81
  if (Array.isArray(result)) return result[0];
74
82
  if ("output" in result) return result;
@@ -106,7 +114,8 @@ const buildPlugin = async ({ pluginDir, outDir, name, projectDir, ignore = [] })
106
114
  ...projectDir === void 0 ? [] : [extensionImports(projectDir, [{ dir: pluginDir }])],
107
115
  pluginStyles(styles, styleCode(pluginDir, target.theme, [outDir, ...ignore])),
108
116
  react(),
109
- tailwindcss()
117
+ tailwindcss(),
118
+ layeredStyles()
110
119
  ],
111
120
  build: {
112
121
  outDir,
@@ -0,0 +1,70 @@
1
+ import postcss from "postcss";
2
+ //#region src/build/plugin-styles.ts
3
+ /**
4
+ * The layer, nested in `utilities`, that holds a plugin's utilities without a variant. Rules outside a nested layer win
5
+ * over the rules inside it, so the app's own utilities win over these, whatever the order of the stylesheets.
6
+ */
7
+ const pluginBaseLayer = "plugin";
8
+ const withoutBrackets = (name) => {
9
+ let depth = 0;
10
+ let out = "";
11
+ for (const char of name) if (char === "[") depth += 1;
12
+ else if (char === "]") depth -= 1;
13
+ else if (depth === 0) out += char;
14
+ return out;
15
+ };
16
+ /** Whether a utility's class name has a variant, such as `md:flex`, `hover:bg-muted` or `[&>*]:p-2`. */
17
+ const hasVariant = (name) => withoutBrackets(name).includes(":");
18
+ const unescape = (name) => name.replace(/\\([0-9a-fA-F]{1,6}) ?|\\(.)/g, (_, hex, char) => hex ? String.fromCodePoint(parseInt(hex, 16)) : char);
19
+ /** The class names in a selector, also those inside :is(), :where() and :not(), unescaped: `.md\:flex` is `md:flex`. */
20
+ const classNames = (selector) => [...selector.matchAll(/\.((?:\\[0-9a-fA-F]{1,6} ?|\\.|[\w-]|[^\x00-\x7f])+)/g)].map(([, name]) => unescape(name));
21
+ const around = (node, children) => {
22
+ const copy = node.clone();
23
+ copy.removeAll();
24
+ return copy.append(children.map((child) => child.clone()));
25
+ };
26
+ const partition = (nodes) => {
27
+ const parts = {
28
+ base: [],
29
+ variant: []
30
+ };
31
+ for (const node of nodes) if (node.type === "rule") {
32
+ const varies = (selector) => classNames(selector).some(hasVariant);
33
+ const base = node.selectors.filter((selector) => !varies(selector));
34
+ const variant = node.selectors.filter(varies);
35
+ if (base.length > 0) parts.base.push(variant.length === 0 ? node : node.clone({ selectors: base }));
36
+ if (variant.length > 0) parts.variant.push(base.length === 0 ? node : node.clone({ selectors: variant }));
37
+ } else if (node.type === "atrule" && [
38
+ "media",
39
+ "supports",
40
+ "container"
41
+ ].includes(node.name) && node.nodes) {
42
+ const inner = partition(node.nodes);
43
+ if (inner.base.length > 0) parts.base.push(around(node, inner.base));
44
+ if (inner.variant.length > 0) parts.variant.push(around(node, inner.variant));
45
+ } else parts.variant.push(node);
46
+ return parts;
47
+ };
48
+ const isUtilities = (node) => node.type === "atrule" && node.name === "layer" && node.params.trim() === "utilities" && node.nodes !== void 0;
49
+ /**
50
+ * A plugin's stylesheet with its utilities without a variant moved into a layer under the app's utilities. The app
51
+ * loads a plugin's stylesheet after its own, where a plugin's `.flex` would otherwise win over the app's `md:block` on
52
+ * the app's own elements. A plugin's variants stay after the app's utilities, so its `hidden md:flex` still works when
53
+ * only the app's stylesheet has `.hidden`.
54
+ */
55
+ const layerPluginUtilities = (css) => {
56
+ const root = postcss.parse(css);
57
+ for (const node of root.nodes.filter(isUtilities)) {
58
+ const { base, variant } = partition(node.nodes);
59
+ const kept = variant.map((child) => child.clone());
60
+ node.removeAll();
61
+ if (base.length > 0) node.append(postcss.atRule({
62
+ name: "layer",
63
+ params: pluginBaseLayer
64
+ }).append(base.map((child) => child.clone())));
65
+ node.append(kept);
66
+ }
67
+ return root.toString();
68
+ };
69
+ //#endregion
70
+ export { classNames, hasVariant, layerPluginUtilities, pluginBaseLayer };
package/dist/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "0.12.5";
2
+ var version = "0.12.6";
3
3
  //#endregion
4
4
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/cli",
3
- "version": "0.12.5",
3
+ "version": "0.12.6",
4
4
  "description": "The protobase command: scaffold, doctor, dev, build and serve a Protobase project.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -34,11 +34,11 @@
34
34
  "dependencies": {
35
35
  "@hono/node-server": "^2.1.3",
36
36
  "@hono/vite-dev-server": "^0.26.1",
37
- "@protobase/layout": "0.12.5",
38
- "@protobase/query": "0.12.5",
39
- "@protobase/schema": "0.12.5",
40
- "@protobase/server": "0.12.5",
41
- "@protobase/ui": "0.12.5",
37
+ "@protobase/layout": "0.12.6",
38
+ "@protobase/query": "0.12.6",
39
+ "@protobase/schema": "0.12.6",
40
+ "@protobase/server": "0.12.6",
41
+ "@protobase/ui": "0.12.6",
42
42
  "@scalar/hono-api-reference": "^0.12.10",
43
43
  "@tailwindcss/vite": "^4.3.3",
44
44
  "@vitejs/plugin-react": "^6.1.2",
@@ -51,6 +51,7 @@
51
51
  "kysely": "^0.29.6",
52
52
  "lightningcss": "^1.33.0",
53
53
  "pg": "^8.23.1",
54
+ "postcss": "^8.5.29",
54
55
  "postgres": "^3.4.9",
55
56
  "ts-morph": "^28.0.0",
56
57
  "vite": "^8.3.3",