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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tss-react",
"version": "4.9.17",
"version": "4.9.18-rc.2",
"description": "Type safe CSS-in-JS API heavily inspired by react-jss",
"repository": {
"type": "git",
Expand Down Expand Up @@ -52,7 +52,7 @@
}
},
"scripts": {
"build": "tsc && tsc -p tsconfig-esm.json",
"build": "tsc && tsc -p tsconfig-esm.json && ts-node src/bin/shim_jsx_element.ts",
"start_spa": "yarn yarn_link && cd src/test/apps/spa && yarn start",
"start_ssr": "yarn yarn_link && cd src/test/apps/ssr && yarn dev",
"start_appdir": "yarn yarn_link && cd src/test/apps/next-appdir && yarn dev",
Expand Down
31 changes: 31 additions & 0 deletions src/bin/shim_jsx_element.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { transformCodebase } from "./tools/transformCodebase";
import { join as pathJoin } from "path";

function shimJsxElement(params: { distDirPath: string }) {
const { distDirPath } = params;

transformCodebase({
srcDirPath: distDirPath,
destDirPath: distDirPath,
transformSourceCode: ({ fileRelativePath, sourceCode }) => {
if (!fileRelativePath.endsWith(".d.ts")) {
return { modifiedSourceCode: sourceCode };
}

let modifiedSourceCode = sourceCode.toString("utf8");

modifiedSourceCode = modifiedSourceCode.replace(
/JSX\.Element/g,
'import("react").ReactElement<any, any>'
);

return {
modifiedSourceCode: Buffer.from(modifiedSourceCode, "utf8")
};
}
});
}

shimJsxElement({
distDirPath: pathJoin(process.cwd(), "dist")
});
119 changes: 119 additions & 0 deletions src/bin/tools/SemVer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
export type SemVer = {
major: number;
minor: number;
patch: number;
rc?: number;
parsedFrom: string;
};

export namespace SemVer {
const bumpTypes = ["major", "minor", "patch", "rc", "no bump"] as const;

export type BumpType = typeof bumpTypes[number];

export function parse(versionStr: string): SemVer {
const match = versionStr.match(
/^v?([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(?:-rc.([0-9]+))?$/
);

if (!match) {
throw new Error(`${versionStr} is not a valid semantic version`);
}

const semVer: Omit<SemVer, "parsedFrom"> = {
major: parseInt(match[1]),
minor: parseInt(match[2]),
patch: (() => {
const str = match[3];

return str === undefined ? 0 : parseInt(str);
})(),
...(() => {
const str = match[4];
return str === undefined ? {} : { rc: parseInt(str) };
})()
};

const initialStr = stringify(semVer);

Object.defineProperty(semVer, "parsedFrom", {
enumerable: true,
get: function () {
const currentStr = stringify(this);

if (currentStr !== initialStr) {
throw new Error(
`SemVer.parsedFrom can't be read anymore, the version have been modified from ${initialStr} to ${currentStr}`
);
}

return versionStr;
}
});

return semVer as any;
}

export function stringify(v: Omit<SemVer, "parsedFrom">): string {
return `${v.major}.${v.minor}.${v.patch}${
v.rc === undefined ? "" : `-rc.${v.rc}`
}`;
}

/**
*
* v1 < v2 => -1
* v1 === v2 => 0
* v1 > v2 => 1
*
*/
export function compare(v1: SemVer, v2: SemVer): -1 | 0 | 1 {
const sign = (diff: number): -1 | 0 | 1 =>
diff === 0 ? 0 : diff < 0 ? -1 : 1;
const noUndefined = (n: number | undefined) => n ?? Infinity;

for (const level of ["major", "minor", "patch", "rc"] as const) {
if (noUndefined(v1[level]) !== noUndefined(v2[level])) {
return sign(noUndefined(v1[level]) - noUndefined(v2[level]));
}
}

return 0;
}

/*
console.log(compare(parse("3.0.0-rc.3"), parse("3.0.0")) === -1 )
console.log(compare(parse("3.0.0-rc.3"), parse("3.0.0-rc.4")) === -1 )
console.log(compare(parse("3.0.0-rc.3"), parse("4.0.0")) === -1 )
*/

export function bumpType(params: {
versionBehind: string | SemVer;
versionAhead: string | SemVer;
}): BumpType | "no bump" {
const versionAhead =
typeof params.versionAhead === "string"
? parse(params.versionAhead)
: params.versionAhead;
const versionBehind =
typeof params.versionBehind === "string"
? parse(params.versionBehind)
: params.versionBehind;

if (compare(versionBehind, versionAhead) === 1) {
throw new Error(
`Version regression ${stringify(versionBehind)} -> ${stringify(
versionAhead
)}`
);
}

for (const level of ["major", "minor", "patch", "rc"] as const) {
if (versionBehind[level] !== versionAhead[level]) {
return level;
}
}

return "no bump";
}
}
35 changes: 35 additions & 0 deletions src/bin/tools/crawl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as fs from "fs";
import { join as pathJoin, relative as pathRelative } from "path";

const crawlRec = (dirPath: string, filePaths: string[]) => {
for (const basename of fs.readdirSync(dirPath)) {
const fileOrDirPath = pathJoin(dirPath, basename);

if (fs.lstatSync(fileOrDirPath).isDirectory()) {
crawlRec(fileOrDirPath, filePaths);

continue;
}

filePaths.push(fileOrDirPath);
}
};

/** List all files in a given directory return paths relative to the dir_path */
export function crawl(params: {
dirPath: string;
returnedPathsType: "absolute" | "relative to dirPath";
}): string[] {
const { dirPath, returnedPathsType } = params;

const filePaths: string[] = [];

crawlRec(dirPath, filePaths);

switch (returnedPathsType) {
case "absolute":
return filePaths;
case "relative to dirPath":
return filePaths.map(filePath => pathRelative(dirPath, filePath));
}
}
40 changes: 40 additions & 0 deletions src/bin/tools/fs.rmSync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as fs from "fs";
import { join as pathJoin } from "path";
import { SemVer } from "./SemVer";

/**
* Polyfill of fs.rmSync(dirPath, { "recursive": true })
* For older version of Node
*/
export function rmSync(
dirPath: string,
options: { recursive: true; force?: true }
) {
if (
SemVer.compare(SemVer.parse(process.version), SemVer.parse("14.14.0")) >
0
) {
fs.rmSync(dirPath, options);
return;
}

const { force = true } = options;

if (force && !fs.existsSync(dirPath)) {
return;
}

const removeDir_rec = (dirPath: string) =>
fs.readdirSync(dirPath).forEach(basename => {
const fileOrDirPath = pathJoin(dirPath, basename);

if (fs.lstatSync(fileOrDirPath).isDirectory()) {
removeDir_rec(fileOrDirPath);
return;
} else {
fs.unlinkSync(fileOrDirPath);
}
});

removeDir_rec(dirPath);
}
89 changes: 89 additions & 0 deletions src/bin/tools/transformCodebase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import * as fs from "fs";
import * as path from "path";
import { crawl } from "./crawl";
import { rmSync } from "./fs.rmSync";

type TransformSourceCode = (params: {
sourceCode: Buffer;
filePath: string;
fileRelativePath: string;
}) =>
| {
modifiedSourceCode: Buffer;
newFileName?: string;
}
| undefined;

/**
* Apply a transformation function to every file of directory
* If source and destination are the same this function can be used to apply the transformation in place
* like filtering out some files or modifying them.
* */
export function transformCodebase(params: {
srcDirPath: string;
destDirPath: string;
transformSourceCode?: TransformSourceCode;
}) {
const { srcDirPath, transformSourceCode } = params;

const isTargetSameAsSource =
path.relative(srcDirPath, params.destDirPath) === "";

const destDirPath = isTargetSameAsSource
? path.join(srcDirPath, "..", "tmp_xOsPdkPsTdzPs34sOkHs")
: params.destDirPath;

fs.mkdirSync(destDirPath, {
recursive: true
});

for (const fileRelativePath of crawl({
dirPath: srcDirPath,
returnedPathsType: "relative to dirPath"
})) {
const filePath = path.join(srcDirPath, fileRelativePath);
const destFilePath = path.join(destDirPath, fileRelativePath);

// NOTE: Optimization, if we don't need to transform the file, just copy
// it using the lower level implementation.
if (transformSourceCode === undefined) {
fs.mkdirSync(path.dirname(destFilePath), {
recursive: true
});

fs.copyFileSync(filePath, destFilePath);

continue;
}

const transformSourceCodeResult = transformSourceCode({
sourceCode: fs.readFileSync(filePath),
filePath,
fileRelativePath
});

if (transformSourceCodeResult === undefined) {
continue;
}

fs.mkdirSync(path.dirname(destFilePath), {
recursive: true
});

const { newFileName, modifiedSourceCode } = transformSourceCodeResult;

fs.writeFileSync(
path.join(
path.dirname(destFilePath),
newFileName ?? path.basename(destFilePath)
),
modifiedSourceCode
);
}

if (isTargetSameAsSource) {
rmSync(srcDirPath, { recursive: true });

fs.renameSync(destDirPath, srcDirPath);
}
}
8 changes: 3 additions & 5 deletions src/makeStyles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@ import type {
MuiThemeStyleOverridesPluginParams,
MuiThemeLike
} from "./mui/themeStyleOverridesPlugin";
// @ts-expect-error: It's not declared but it's there.
import { __unsafe_useEmotionCache } from "@emotion/react";

declare module "@emotion/react" {
export function __unsafe_useEmotionCache(): EmotionCache | null;
}

import { __unsafe_useEmotionCache as useContextualCache } from "@emotion/react";
const useContextualCache: () => EmotionCache | null = __unsafe_useEmotionCache;

let counter = 0;

Expand Down
Loading