Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[node-build-scripts] break: refactor into ES modules #5630

Merged
merged 5 commits into from
Sep 30, 2022
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
8 changes: 4 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,23 @@ aliases:

- &restore-node-modules-cache
name: Restore node_modules cache
key: v5-yarn-deps-{{ checksum "yarn.lock" }}
key: v6-yarn-deps-{{ checksum "yarn.lock" }}

- &restore-yarn-cache
name: Restore yarnpkg cache
key: v5-yarn-cache
key: v6-yarn-cache

- &save-node-modules-cache
name: Save node_modules cache
paths:
- node_modules
key: v5-yarn-deps-{{ checksum "yarn.lock" }}
key: v6-yarn-deps-{{ checksum "yarn.lock" }}

- &save-yarn-cache
name: Save yarnpkg cache
paths:
- ~/.cache/yarn
key: v5-yarn-cache
key: v6-yarn-cache

references:
reports_path: &reports_path
Expand Down
3 changes: 2 additions & 1 deletion packages/node-build-scripts/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"parserOptions": {
"ecmaVersion": 2020
"ecmaVersion": 2022,
"sourceType": "module"
},
"rules": {
"no-console": "off"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,26 @@
*/

// @ts-check
const fs = require("fs");
const path = require("path");

import { existsSync, readFileSync } from "node:fs";
import { join, resolve } from "node:path";
import { cwd, exit } from "node:process";
import { pathToFileURL } from "node:url";

// asserts that all main fields in package.json reference existing files
const PACKAGE_MAIN_FIELDS = ["main", "module", "style", "types", "typings", "unpkg"];
const manifest = require(path.resolve(process.cwd(), "./package.json"));

// TODO(adahiya): replace this with `await import("./package.json", { assert: { type: "json" } })` in Node 17.5+
const manifest = JSON.parse(readFileSync(pathToFileURL(join(cwd(), "package.json")), { encoding: "utf8" }));

for (const field of PACKAGE_MAIN_FIELDS.filter(f => manifest[f] !== undefined)) {
if (!fs.existsSync(path.resolve(process.cwd(), manifest[field]))) {
if (!existsSync(resolve(cwd(), manifest[field]))) {
console.error(
`[node-build-scripts] Failed to validate package layout: expected '${manifest[field]}' to exist.`,
);
process.exit(1);
exit(1);
}
}

console.info("[node-build-scripts] Successfully validated package layout.");
process.exit(0);
exit(0);
8 changes: 0 additions & 8 deletions packages/node-build-scripts/constants.js

This file was deleted.

6 changes: 6 additions & 0 deletions packages/node-build-scripts/constants.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Copyright 2017 Palantir Technologies, Inc. All rights reserved.
*/

export const COPYRIGHT_HEADER = "/*\n * Copyright 2022 Palantir Technologies, Inc. All rights reserved.\n */\n";
export const USE_MATH_RULE = `@use "sass:math";\n`;
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,50 @@
*/

// @ts-check
"use strict";

const { spawn } = require("cross-spawn");
const fs = require("fs");
const glob = require("glob");
const path = require("path");
import { spawn } from "cross-spawn";
import glob from "glob";
import { createWriteStream } from "node:fs";
import { basename, resolve } from "node:path";
import { argv, cwd, env, exit, stderr, stdout } from "node:process";

const { junitReportPath } = require("./utils");
import { junitReportPath } from "./utils.mjs";

let format = "codeframe";
let out;
let outputStream = process.stdout;
if (process.env.JUNIT_REPORT_PATH != null) {
let outputPath;
let outputStream = stdout;
if (env.JUNIT_REPORT_PATH != null) {
format = "junit";
out = junitReportPath("eslint");
console.info(`ESLint report will appear in ${out}`);
outputPath = junitReportPath("eslint");
console.info(`[node-build-scripts] ESLint report will appear in ${outputPath}`);
// @ts-ignore
outputStream = fs.createWriteStream(out, { flags: "w+" });
outputStream = createWriteStream(outputPath, { flags: "w+" });
}

// additional args provided to es-lint script
const additionalArgs = process.argv.filter(a => {
const additionalArgs = argv.filter(a => {
// exclude engine and script name
return ["node", "node.exe", "es-lint", "es-lint.js"].every(s => path.basename(a) !== s);
return ["node", "node.exe", "es-lint", "es-lint.js"].every(s => basename(a) !== s);
});

const commandLineOptions = ["--color", "-f", format, ...additionalArgs];

// ESLint will fail if provided with no files, so we expand the glob before running it
const fileGlob = "{src,test}/**/*.{ts,tsx}";
const absoluteFileGlob = path.resolve(process.cwd(), fileGlob);
const absoluteFileGlob = resolve(cwd(), fileGlob);
const anyFilesToLint = glob.sync(absoluteFileGlob);
if (anyFilesToLint.length === 0) {
console.log(`[node-build-scripts] Not running ESLint because no files match the glob "${fileGlob}"`);
process.exit();
exit();
}

process.env.LINT_SCRIPT = "true";
env.LINT_SCRIPT = "true";

const eslint = spawn("eslint", [...commandLineOptions, absoluteFileGlob]);

eslint.stdout.pipe(outputStream);
eslint.stderr.pipe(process.stderr);
eslint.stderr.pipe(stderr);

eslint.on("close", code => {
process.exitCode = code;
exit(code ?? undefined);
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,23 @@
*/

// @ts-check
const fs = require("fs");
const getSassVars = require("get-sass-vars");
const path = require("path");
const prettier = require("prettier");
const yargs = require("yargs/yargs");

const { COPYRIGHT_HEADER, USE_MATH_RULE } = require("./constants");
import getSassVars from "get-sass-vars";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { resolve } from "node:path";
import { argv, cwd } from "node:process";
import prettier from "prettier";
import yargs from "yargs/yargs";

const SRC_DIR = path.resolve(process.cwd(), "./src");
const DEST_DIR = path.resolve(process.cwd(), "./lib");
import { COPYRIGHT_HEADER, USE_MATH_RULE } from "./constants.mjs";

main();
const SRC_DIR = resolve(cwd(), "./src");
const DEST_DIR = resolve(cwd(), "./lib");

await main();

async function main() {
const args = yargs(process.argv.slice(2))
const args = yargs(argv.slice(2))
.option("outputFileName", {
alias: "o",
default: "variables",
Expand All @@ -42,13 +44,13 @@ async function main() {
* and gets compiled output from `get-sass-vars`.
*
* @param {string[]} inputSources
* @returns {Promise<{parsedVars: object, varsInBlocks: Set<string>[], varsWithDefaultFlag: Set<string>}>} output compiled variable values and grouped variable blocks
* @returns {Promise<{parsedVars: object, varsInBlocks: Set<string | undefined>[], varsWithDefaultFlag: Set<string | undefined>}>} output compiled variable values and grouped variable blocks
*/
async function getParsedVars(inputSources) {
const stripCssComments = (await import("strip-css-comments")).default;
// concatenate sources
let cleanedInput = inputSources.reduce((str, currentFilename) => {
return str + fs.readFileSync(`${SRC_DIR}/${currentFilename}`).toString();
return str + readFileSync(`${SRC_DIR}/${currentFilename}`).toString();
}, "");
// strip comments, clean up for consumption
cleanedInput = stripCssComments(cleanedInput);
Expand All @@ -59,27 +61,26 @@ async function getParsedVars(inputSources) {
.replace(/\n{3,}/g, "\n\n");
cleanedInput = [USE_MATH_RULE, cleanedInput].join("\n");

// @ts-ignore, issues with types in `get-sass-vars`
const getSassVarsSync = getSassVars.sync;

const parsedVars = getSassVarsSync(cleanedInput, {
sassOptions: { functions: require("./node-sass-json-functions.js") },
const functions = (await import("./node-sass-json-functions.mjs")).default;
const parsedVars = await getSassVars(cleanedInput, {
// @ts-ignore - `get-sass-vars` types do not capture the type constraints possible with the library
sassOptions: { functions },
});

// get variable blocks for separating variables in output
const varsInBlocks = cleanedInput
.split("\n\n")
.map(
block =>
new Set([...block.matchAll(/(?<varName>\$[-_a-zA-z0-9]+)(?::)/g)].map(match => match.groups.varName)),
new Set([...block.matchAll(/(?<varName>\$[-_a-zA-z0-9]+)(?::)/g)].map(match => match.groups?.varName)),
);

// `getSassVarsSync` strips `!default` flags from the output, so we need to determine which
// variables had those flags set here and pass it on
const varsWithDefaultFlag = new Set(
[...cleanedInput.matchAll(/(?<varName>\$[-_a-zA-z0-9]+)(?::)(?<varValue>[\s\S]+?);/gm)]
.map(match => [match.groups.varName, match.groups.varValue.trim()])
.filter(([, varValue]) => varValue.endsWith("!default"))
.map(match => [match.groups?.varName, match.groups?.varValue.trim()])
.filter(([, varValue]) => varValue?.endsWith("!default"))
.map(([varName]) => varName),
);

Expand All @@ -106,7 +107,7 @@ function convertParsedValueToOutput(value, outputType) {
// Objects are map variables, formatted like:
// https://lesscss.org/features/#maps-feature
// https://sass-lang.com/documentation/values/maps
if (typeof value === "object") {
if (value !== null && typeof value === "object") {
return outputType === "scss"
? `(${Object.entries(value).reduce(
(str, [key, val]) => `${str}\n"${key}": ${convertParsedValueToOutput(val, outputType)},`,
Expand All @@ -129,7 +130,7 @@ function convertParsedValueToOutput(value, outputType) {
* Pulls together variables from the specified Sass source files, sanitizes them for consumption,
* and writes to an output file.
*
* @param {{parsedVars: object, varsInBlocks: Set<string>[], varsWithDefaultFlag: Set<string>}} parsedInput
* @param {{parsedVars: object, varsInBlocks: Set<string | undefined>[], varsWithDefaultFlag: Set<string | undefined>}} parsedInput
* @param {string} outputFilename
* @param {boolean} retainDefault whether to retain `!default` flags on variables
* @returns {string} output Sass contents
Expand All @@ -151,17 +152,17 @@ function generateScssVariables(parsedInput, outputFilename, retainDefault) {

const formattedVariablesScss = prettier.format(variablesScss, { parser: "less" });

if (!fs.existsSync(`${DEST_DIR}/scss`)) {
fs.mkdirSync(`${DEST_DIR}/scss`, { recursive: true });
if (!existsSync(`${DEST_DIR}/scss`)) {
mkdirSync(`${DEST_DIR}/scss`, { recursive: true });
}
fs.writeFileSync(`${DEST_DIR}/scss/${outputFilename}.scss`, formattedVariablesScss);
writeFileSync(`${DEST_DIR}/scss/${outputFilename}.scss`, formattedVariablesScss);
return formattedVariablesScss;
}

/**
* Takes in variable values from compiled sass vars, converts them to Less and writes to an output file.
*
* @param {{parsedVars: object, varsInBlocks: Set<string>[]}} parsedInput
* @param {{parsedVars: object, varsInBlocks: Set<string | undefined>[]}} parsedInput
* @param {string} outputFilename
* @returns {void}
*/
Expand Down Expand Up @@ -197,8 +198,8 @@ function generateLessVariables(parsedInput, outputFilename) {

const formattedVariablesLess = prettier.format(variablesLess, { parser: "less" });

if (!fs.existsSync(`${DEST_DIR}/less`)) {
fs.mkdirSync(`${DEST_DIR}/less`, { recursive: true });
if (!existsSync(`${DEST_DIR}/less`)) {
mkdirSync(`${DEST_DIR}/less`, { recursive: true });
}
fs.writeFileSync(`${DEST_DIR}/less/${outputFilename}.less`, formattedVariablesLess);
writeFileSync(`${DEST_DIR}/less/${outputFilename}.less`, formattedVariablesLess);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

"use strict";

const isPlainObject = require("is-plain-obj");
const parseColor = require("parse-color");
const parseUnit = require("parse-css-dimension");
const rgbHex = require("rgb-hex");
const round = require("round-to");
const sass = require("sass");
const shortHexColor = require("shorten-css-hex");
import isPlainObject from "is-plain-obj";
import parseColor from "parse-color";
import parseUnit from "parse-css-dimension";
import rgbHex from "rgb-hex";
import round from "round-to";
import sass from "sass";
import shortHexColor from "shorten-css-hex";

// eslint-disable-next-line no-underscore-dangle
function _interopDefaultLegacy(e) {
Expand Down Expand Up @@ -283,9 +281,8 @@ function decode(value) {
}

/** @type {{ 'json-encode($value, $quotes: true, $precision: 5)': typeof encode, 'json-decode($value)': typeof decode }} */
const api = {
// eslint-disable-next-line import/no-default-export
export default {
"json-encode($value, $quotes: true, $precision: 5)": encode,
"json-decode($value)": decode,
};

module.exports = api;
11 changes: 7 additions & 4 deletions packages/node-build-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
"test": "exit 0"
},
"bin": {
"assert-package-layout": "./assert-package-layout.js",
"assert-package-layout": "./assert-package-layout.mjs",
"css-dist": "./css-dist.sh",
"es-lint": "./es-lint.js",
"generate-css-variables": "./generate-css-variables.js",
"es-lint": "./es-lint.mjs",
"generate-css-variables": "./generate-css-variables.mjs",
"sass-compile": "./sass-compile.sh",
"sass-lint": "./sass-lint.js"
"sass-lint": "./sass-lint.mjs"
},
"dependencies": {
"autoprefixer": "^10.4.4",
Expand Down Expand Up @@ -42,6 +42,9 @@
"@types/fs-extra": "~9.0.13",
"@types/yargs": "~17.0.13"
},
"engines": {
"node": ">=16"
},
"repository": {
"type": "git",
"url": "git@github.com:palantir/blueprint.git",
Expand Down
Loading