@surplus/esbuild 1.2.0 → 2.0.0

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.
package/index.mjs CHANGED
@@ -1,60 +1,2 @@
1
- import fsp from "node:fs/promises";
2
-
3
- import { compile } from "@surplus/compiler";
4
-
5
- const BASE_RESULT = {
6
- pluginName: "Surplus Compiler",
7
- };
8
-
9
- export default (opts) => ({
10
- name: "surplus",
11
- setup(build) {
12
- const jsFileExtensions = [".js", ".jsx", ".mjs", ".cjs"];
13
- const tsFileExtensions = [".ts", ".tsx"];
14
-
15
- const fileExtensions = [
16
- ...jsFileExtensions.map((e) => [e, false]),
17
- ...tsFileExtensions.map((e) => [e, true]),
18
- ];
19
-
20
- for (const [ext, ts] of fileExtensions) {
21
- build.onLoad({ filter: new RegExp(`\\${ext}$`) }, async (args) => {
22
- try {
23
- const source = await fsp.readFile(args.path, "utf8");
24
-
25
- const result = compile({
26
- source,
27
- minify: false,
28
- sourcemapFilename: args.path,
29
- typescript: ts,
30
- ...opts,
31
- });
32
-
33
- if (result.errors.length > 0) {
34
- return {
35
- ...BASE_RESULT,
36
- errors: result.errors?.map((err) => ({
37
- text: err,
38
- })),
39
- };
40
- }
41
-
42
- return {
43
- ...BASE_RESULT,
44
- contents: result.code,
45
- warnings: result.warnings?.map((err) => ({
46
- text: err,
47
- })),
48
- loader: "default",
49
- };
50
- } catch (err) {
51
- // Handle any errors from the transpiler
52
- return {
53
- ...BASE_RESULT,
54
- errors: [{ text: err.message }],
55
- };
56
- }
57
- });
58
- }
59
- },
60
- });
1
+ export { default as surplus } from "./lib/surplus.mjs";
2
+ export { default as surplusCss } from "./lib/css.mjs";
package/lib/css.mjs ADDED
@@ -0,0 +1,177 @@
1
+ import { promises as fsp } from "fs";
2
+ import path from "path";
3
+
4
+ import css from "css";
5
+ import * as cssWhat from "css-what";
6
+ import { camelCase } from "change-case";
7
+
8
+ const toArrayBuffer = (text) => new TextEncoder("utf-8").encode(text);
9
+
10
+ const camelize = (str) => camelCase(str, { transform: camelCase });
11
+
12
+ async function processCSS(contents, uid, mappings) {
13
+ const ast = css.parse(contents);
14
+
15
+ let priority = 0;
16
+
17
+ ast.stylesheet.rules = ast.stylesheet.rules
18
+ .map((rule) => {
19
+ switch (rule.type) {
20
+ case "rule":
21
+ const { selectors, ...rest } = rule;
22
+
23
+ let globalize = false;
24
+ let ignore = false;
25
+
26
+ const result = {
27
+ selectors: selectors.map((selector) =>
28
+ cssWhat.stringify(
29
+ cssWhat.parse(selector).map((tokens) =>
30
+ tokens
31
+ .map((t) => {
32
+ if (
33
+ t.type === "tag" &&
34
+ t.name === "@global"
35
+ ) {
36
+ globalize = true;
37
+ return false;
38
+ } else if (
39
+ t.type === "attribute" &&
40
+ t.name === "class"
41
+ ) {
42
+ const newValue = globalize
43
+ ? t.value
44
+ : `${t.value}-${uid}`;
45
+ mappings[camelize(t.value)] =
46
+ newValue;
47
+ return {
48
+ ...t,
49
+ value: newValue,
50
+ };
51
+ } else if (
52
+ t.type === "tag" &&
53
+ t.name === "@meta"
54
+ ) {
55
+ // Don't emit it in the resulting CSS.
56
+ ignore = true;
57
+
58
+ for (const decl of rule.declarations) {
59
+ switch (decl.property) {
60
+ case "priority":
61
+ priority =
62
+ parseFloat(
63
+ decl.value,
64
+ 10,
65
+ );
66
+ break;
67
+ }
68
+ }
69
+ }
70
+
71
+ return t;
72
+ })
73
+ .filter(Boolean),
74
+ ),
75
+ ),
76
+ ),
77
+ ...rest,
78
+ };
79
+
80
+ return ignore ? null : result;
81
+ default:
82
+ return rule;
83
+ }
84
+ })
85
+ .filter(Boolean);
86
+
87
+ return {
88
+ content: css.stringify(ast),
89
+ priority,
90
+ };
91
+ }
92
+
93
+ export default ({ outfile } = {}) => {
94
+ return {
95
+ name: "Surplus CSS Modules",
96
+ setup(build) {
97
+ const cssFiles = new Map();
98
+ const cssFilesList = [];
99
+
100
+ build.onLoad({ filter: /\.css$/ }, async (args) => {
101
+ const contents = await fsp.readFile(args.path, "utf-8");
102
+
103
+ let mappings = {};
104
+
105
+ if (cssFiles.has(args.path)) {
106
+ ({ mappings } = cssFiles.get(args.path));
107
+ } else {
108
+ const { content, priority } = await processCSS(
109
+ contents,
110
+ cssFiles.size,
111
+ mappings,
112
+ );
113
+
114
+ cssFiles.set(args.path, {
115
+ content,
116
+ mappings,
117
+ });
118
+
119
+ cssFilesList.push({ pathname: args.path, priority });
120
+ }
121
+
122
+ return {
123
+ contents: Object.entries(mappings)
124
+ .map(
125
+ (e) =>
126
+ `export const ${e[0]} = ${JSON.stringify(e[1])};`,
127
+ )
128
+ .join("\n"),
129
+ loader: "js",
130
+ };
131
+ });
132
+
133
+ build.onEnd(async (result) => {
134
+ const outPath = outfile || build.initialOptions.outfile;
135
+ if (!outPath) {
136
+ // We need to know where to put it based on its sibling output files.
137
+ return {
138
+ warnings: [
139
+ "not emitting a .css file because it appears there are no other output files (or an error occurred somewhere else in the build)",
140
+ ],
141
+ };
142
+ }
143
+
144
+ const buildDir = path.dirname(outPath);
145
+
146
+ cssFilesList.sort((a, b) => a.priority - b.priority);
147
+
148
+ const chunks = [];
149
+
150
+ for (const { pathname } of cssFilesList) {
151
+ const cssFile = cssFiles.get(pathname);
152
+ chunks.push(`/* ${path.relative(buildDir, pathname)} */`);
153
+ chunks.push(cssFile.content);
154
+ chunks.push("");
155
+ }
156
+
157
+ let outText = chunks.join("\n");
158
+
159
+ if (build.initialOptions.minify) {
160
+ outText = css.stringify(css.parse(outText), {
161
+ compress: true,
162
+ });
163
+ }
164
+
165
+ await fsp.writeFile(
166
+ path.join(
167
+ buildDir,
168
+ path.basename(outPath, path.extname(outPath)) + ".css",
169
+ ),
170
+ outText,
171
+ );
172
+
173
+ return { warnings: [new Error("this is a warning")] };
174
+ });
175
+ },
176
+ };
177
+ };
@@ -0,0 +1,64 @@
1
+ import fsp from "node:fs/promises";
2
+
3
+ import { compile } from "@surplus/compiler";
4
+
5
+ const BASE_RESULT = {
6
+ pluginName: "Surplus Compiler",
7
+ };
8
+
9
+ export default (opts) => ({
10
+ name: "Surplus Compiler",
11
+ setup(build) {
12
+ const jsFileExtensions = [".js", ".jsx", ".mjs", ".cjs"];
13
+ const tsFileExtensions = [".ts", ".tsx"];
14
+
15
+ const fileExtensions = [
16
+ ...jsFileExtensions.map((e) => [e, false]),
17
+ ...tsFileExtensions.map((e) => [e, true]),
18
+ ];
19
+
20
+ for (const [ext, ts] of fileExtensions) {
21
+ build.onLoad({ filter: new RegExp(`\\${ext}$`) }, async (args) => {
22
+ try {
23
+ const source = await fsp.readFile(args.path, "utf8");
24
+
25
+ const result = compile({
26
+ source,
27
+ minify: false,
28
+ sourcemapFilename: args.path,
29
+ typescript: ts,
30
+ ...opts,
31
+ });
32
+
33
+ if (result.errors.length > 0) {
34
+ return {
35
+ ...BASE_RESULT,
36
+ errors: result.errors?.map((err) => ({
37
+ text: err,
38
+ })),
39
+ warnings: result.warnings?.map((err) => ({
40
+ text: err,
41
+ })),
42
+ loader: "default",
43
+ };
44
+ }
45
+
46
+ return {
47
+ ...BASE_RESULT,
48
+ contents: result.code,
49
+ warnings: result.warnings?.map((err) => ({
50
+ text: err,
51
+ })),
52
+ loader: "default",
53
+ };
54
+ } catch (err) {
55
+ // Handle any errors from the transpiler
56
+ return {
57
+ ...BASE_RESULT,
58
+ errors: [{ text: err.message }],
59
+ };
60
+ }
61
+ });
62
+ }
63
+ },
64
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@surplus/esbuild",
3
- "version": "1.2.0",
3
+ "version": "2.0.0",
4
4
  "description": "Surplus framework ESBuild plugin",
5
5
  "author": "Josh Junon (https://github.com/qix-)",
6
6
  "license": "MIT",
@@ -20,15 +20,20 @@
20
20
  ],
21
21
  "scripts": {
22
22
  "format": "prettier -w .",
23
- "lint": "prettier -c ."
23
+ "lint": "prettier -c .",
24
+ "test": "cd test && node esbuild.mjs"
24
25
  },
25
26
  "files": [
27
+ "lib/",
26
28
  "index.mjs",
27
29
  "LICENSE",
28
30
  "README.md"
29
31
  ],
30
32
  "dependencies": {
31
- "@surplus/compiler": "^1.2.0"
33
+ "@surplus/compiler": "^1.3.0",
34
+ "change-case": "^5.4.4",
35
+ "css": "^3.0.0",
36
+ "css-what": "^7.0.0"
32
37
  },
33
38
  "engines": {
34
39
  "node": "^12.17.0 || ^14.13 || >=16.0.0"
@@ -37,6 +42,8 @@
37
42
  "access": "public"
38
43
  },
39
44
  "devDependencies": {
45
+ "@surplus/s": "^1.2.0",
46
+ "esbuild": "^0.27.2",
40
47
  "prettier": "^3.6.2"
41
48
  }
42
49
  }