Skip to content

Commit

Permalink
build: update generation scripts (#1139)
Browse files Browse the repository at this point in the history
* build: update generation scripts

* ci: add `gen-check` workflow
  • Loading branch information
mlmoravek authored Dec 2, 2024
1 parent d560007 commit ee1e91e
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 245 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ jobs:
node-version: 22.x
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies 📦
run: npm install
run: npm install
- name: Build lib 🛠️
run: npm run build:lib
28 changes: 28 additions & 0 deletions .github/workflows/gen-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: 'Check if generated files are up to date'
on:
pull_request:
branches: [ develop ]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22.x
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies 📦
run: npm install
- name: Generate files 🧐
run: npm run gen
- name: Check for changes
run: |
changes=$(git status --porcelain)
# Check for changes in regenerated files
if ! test -z "$changes"
then
echo "Generated files not up to date. Perhaps you forgot to run `npm run gen`?"
echo "$changes"
exit 1
fi
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
node-version: 22.x
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies 📦
run: npm install
run: npm install
- name: Run unit tests 🧪
run: npm run test

84 changes: 38 additions & 46 deletions .scripts/gen-comp-types.mjs → .scripts/gen-comp-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@ import process from 'process';

import { createChecker } from "vue-component-meta";

import { componentDirectory, getFolders, getComponents, exist } from "./utils.mjs";
import { getComponents, fileExist, getFolders } from "../packages/docs/src/utils.ts";

const replaceValues = [
[" SortDirection", ' "asc" | "desc"']
];

const __dirname = process.cwd()

if(!exist(path.resolve(__dirname, componentDirectory)))
const componentDirectory = './packages/oruga/src/components';

if (!fileExist(path.resolve(__dirname, componentDirectory)))
throw new Error("Path not exist: " + componentDirectory);

console.log("Creating vue-component-meta checker...")
Expand All @@ -37,70 +35,70 @@ const components = component_folders.map(folder => {

// get all configurable props from all components in folder
const props = folderComponents.flatMap(comp => {
const file = comp+".vue";
const file = comp + ".vue";
const componentPath = path.resolve(__dirname, componentDirectory, folder, file);
let meta = checker.getComponentMeta(componentPath);
if(!meta.props.length) {

if (!meta.props.length) {
console.warn(`Failure parsing component '${name}': no properties found.`);
console.log("Recreating vue-component-meta checker...")
// Recreate component meta checker
// Due to some inconsistencies and unexpected empty extracted props,
// creating a new checker helps to extract the props.
// The reason could be some internal memory out of bound exceptions.
checker = createChecker(
path.resolve(__dirname, './packages/oruga/tsconfig.app.json'),
{ forceUseTs: true, printer: { newLine: 1 } },
);
meta = checker.getComponentMeta(componentPath);
}

return meta.props.filter(prop => {
// filter only class props and configurable props
if(prop.name.includes("Class")) return true;
if(prop.default?.includes("getOption")) {
const path = prop.default.match(/"(.*?)"/)[0];
if (prop.name.includes("Class")) return true;
if (prop.default?.includes("getDefault")) {
const path = (prop.default.match(/"(.*?)"/) || [""])[0];
return path.includes(".");
}
return false;
}).map(prop => {
// remove undefined because we wrap the object with partial
if(prop.type.includes("| undefined"))
if (prop.type.includes("| undefined"))
prop.type = prop.type.replace(" | undefined", '');

// change type for class props
if(prop.type === "ComponentClass")
if (prop.type === "ComponentClass")
prop.type = "ClassDefinition";

if(prop.name.includes("Classes")) {
if (prop.name.includes("Classes")) {
prop.type = 'Record<string, any>';
return prop;
}

// change property name based on config path
if(prop.default && prop.default?.includes("getOption")) {
let name = prop.default.match(/"(.*?)"/)[0];
name = name.substring(1, name.length-1);
if (prop.default && prop.default?.includes("getDefault")) {
let name = (prop.default.match(/"(.*?)"/) || [""])[0];
name = name.substring(1, name.length - 1);
const split = name.split(".");
name = split.length == 2 ? split[1] : split[0];
if(prop.name !== name)
if (prop.name !== name)
prop.name = name;
}

// sort union types
if (prop.type.includes(" | ") && !prop.type.includes("(") && !prop.type.includes("["))
prop.type = prop.type
.split(" | ")
.sort((a, b) => a.localeCompare(b))
.join(" | ");

return prop;
})
})
// filter duplicates
.filter((item, idx, self) =>
idx === self.findIndex(p => p.name === item.name)
)
// filter duplicates
.filter((item, idx, self) =>
idx === self.findIndex(p => p.name === item.name)
)

console.log(`Processed '${name}' component with ${props.length} global props.`);
return { name, props };
})
.sort((a,b) => a.name.localeCompare(b.name))
// sort components by name
.sort((a, b) => a.name.localeCompare(b.name))

console.log(`Processed ${components.length} components.`);

let code = `import type {
ClassDefinition,
ComponentConfigBase,
Expand All @@ -110,25 +108,19 @@ let code = `import type {
// Auto generated component theme config definition
declare module "../index" {
interface OrugaOptions {
${components.map(({name, props}) =>
`${name.toLowerCase()}?: ComponentConfigBase &
Partial<{${
props.map(prop =>`
${components.map(({ name, props }) =>
`${name.toLowerCase()}?: ComponentConfigBase &
Partial<{${props.map(prop => `
/** ${prop.description} */
${prop.name}: ${prop.type};`
).join("")
}
).join("")
}
}>;`
).join(`
).join(`
`)}
}
}
`;

// replace lookup values
replaceValues.forEach((lookup) => {
code = code.replaceAll(lookup[0], lookup[1]);
})

const file = path.resolve(__dirname, componentDirectory, "types.ts");
fs.writeFileSync(file, code, 'utf-8');
Expand Down
12 changes: 7 additions & 5 deletions .scripts/gen-volar-dts.mjs → .scripts/gen-volar-dts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@ import fs from 'fs'
import path from 'path'
import process from 'process'

import { componentDirectory, getComponents, exist } from "./utils.mjs";
import { getComponents, fileExist } from "../packages/docs/src/utils.ts";

const __dirname = process.cwd();

function generateComponentsType (module, file) {
if(!exist(path.resolve(__dirname, componentDirectory)))
const componentDirectory = './packages/oruga/src/components';

function generateComponentsType(module: string, file: string): void {
if (!fileExist(path.resolve(__dirname, componentDirectory)))
throw new Error("Path not exist: " + componentDirectory);

const globalComponents = getComponents(componentDirectory);

const components = {}
globalComponents
// add global O prefix
// add global "O" prefix
.map((dir) => "O" + dir)
// add type declaration
.forEach((key) => {
Expand All @@ -42,7 +44,7 @@ export {};
`;

fs.writeFileSync(path.resolve(__dirname, file), code, 'utf-8')

console.log(`File '${file}' generated.`);
}

Expand Down
10 changes: 5 additions & 5 deletions .scripts/sync-version.js → .scripts/sync-version.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const replace = require('replace-in-file')
import replace from 'replace-in-file';

const jsonPaths = [
'package-lock.json',
Expand All @@ -10,7 +10,7 @@ const version = require('../package.json').version

const configJsonOptions = [{
files: jsonPaths,
from: /"name": "@oruga-ui\/(.*)",([^"]*)"version": .+/ig,
from: /"name": "@oruga-ui\/(.*)",([^"]*)"version": .+/ig,
to: (match) => match.replace(/"version": .+/i, `"version": "${version}",`),
},
{
Expand All @@ -19,13 +19,13 @@ const configJsonOptions = [{
to: (match) => match.replace(/oruga-next": "(.*)",/i, `oruga-next": "${version}",`),
}]

const replaceInFile = (config) =>
replace.sync(config).map((el) => el.file);
const replaceInFile = (config) =>
replace.sync(config).map((el) => el.file);

try {
configJsonOptions.forEach(options => replaceInFile(options));
console.info('Modified files:', jsonPaths.join(', '));
} catch (error) {
console.error(e);
console.error(error);
process.exit(1);
}
45 changes: 0 additions & 45 deletions .scripts/utils.mjs

This file was deleted.

3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,23 @@
"build:lib:watch": "npm run build:lib:watch --workspace @oruga-ui/oruga-next",
"build:examples": "npm run build --workspace @oruga-ui/examples",
"gen": "npm run gen:types && npm run gen:volar && npm run gen:docs",
"gen:volar": "node .scripts/gen-volar-dts.mjs --bundle --platform=node",
"gen:types": "node .scripts/gen-comp-types.mjs --bundle --platform=node",
"gen:volar": "tsx .scripts/gen-volar-dts.ts",
"gen:types": "tsx .scripts/gen-comp-types.ts",
"gen:docs": "npm run docs:gen --workspace @oruga-ui/docs-next",
"publish:examples": "npm run publish:examples --workspace @oruga-ui/examples",
"publish:examples:pre": "npm run publish:examples:pre --workspace @oruga-ui/examples",
"publish:lib": "npm run publish:lib --workspace @oruga-ui/oruga-next",
"publish:lib:pre": "npm run publish:lib:pre --workspace @oruga-ui/oruga-next",
"release": "npm run version && npm run changelog",
"version": "node .scripts/sync-version.js && git add .",
"version": "tsx .scripts/sync-version.ts && git add .",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md",
"postversion": "echo \"You can now publish your tag with 'git push --follow-tags'\""
},
"devDependencies": {
"concurrently": "^9.0.1",
"conventional-changelog": "^6.0.0",
"conventional-changelog-cli": "^5.0.0",
"replace-in-file": "^7.1.0"
"replace-in-file": "^7.1.0",
"tsx": "^4.19.2"
}
}
4 changes: 1 addition & 3 deletions packages/docs/src/docgen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import docgen, {
defineConfig,
type DocgenCLIConfig,
} from "vue-docgen-cli/lib/docgen";
import type { FileEventType } from "vue-docgen-cli/lib/config";
import { findFileCaseInsensitive, getFilenameWithoutExtension } from "./utils";
import { createVueComponentMetaChecker } from "./parser/vue-component-meta-helper";
import { createThemeDocs } from "./themes-helper";
Expand Down Expand Up @@ -74,8 +73,7 @@ export async function run(): Promise<void> {
docsFolder: "packages/docs",
defaultExamples: false,
ignore: IGNORE_COMPONENTS,
propsParser: (filePath: string, opts, event?: FileEventType) =>
parser(checker, filePath, event),
propsParser: (filePath: string) => parser(checker, filePath),
templates: {
props: renderProps,
slots: renderSlots,
Expand Down
7 changes: 0 additions & 7 deletions packages/docs/src/parser/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { type ComponentMetaChecker } from "vue-component-meta";
import type { ComponentDoc } from "vue-docgen-api";
import { mapProps, vueComponentMeta } from "./vue-component-meta-helper";
import { vueDocgenApi } from "./vue-docgen-api-helper";
import { getFilenameWithoutExtension } from "../utils";
import type { FileEventType } from "vue-docgen-cli/lib/config";

const META_PROP_IGNORE = ["key", "ref", "ref_for", "ref_key", "class", "style"];

Expand All @@ -16,12 +14,7 @@ const META_PROP_IGNORE = ["key", "ref", "ref_for", "ref_key", "class", "style"];
export async function parser(
checker: ComponentMetaChecker,
filePath: string,
event?: FileEventType,
): Promise<ComponentDoc[]> {
const component = getFilenameWithoutExtension(filePath);

console.debug(`Processing component ${component} in mode ${event}...`);

// analyse component with vue-component-meta
const metaSources = await vueComponentMeta(checker, filePath);

Expand Down
1 change: 1 addition & 0 deletions packages/docs/src/parser/vue-component-meta-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export function createVueComponentMetaChecker(
printer: { newLine: 1 },
};

console.log("Creating vue-component-meta checker...");
return createChecker(tsconfigPath, checkerOptions);
}

Expand Down
Loading

0 comments on commit ee1e91e

Please sign in to comment.