Commit 326519be authored by Anthon Holmqvist's avatar Anthon Holmqvist Committed by Anthon Holmqvist
Browse files

feat: add first working prototype

the prototype will find all vue components with an
<htmlvalidate> block and output content as htmlvalidate rules
for each component.

currently there is not many checks and the code expects a
few things to exist for it to work.

the component name/rule name will be determined in the following order;
name property in the component, followed by the filename. if nothing
is found it will use a default NameNotFound name.

rule content is currently only validated that it is a valid JSON.
parent 5cd9c4c4
Loading
Loading
Loading
Loading
+48 −6
Original line number Diff line number Diff line
@@ -543,12 +543,27 @@
        "@types/istanbul-lib-report": "*"
      }
    },
    "@types/json-schema": {
      "version": "7.0.4",
      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz",
      "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==",
      "dev": true
    },
    "@types/node": {
      "version": "13.7.7",
      "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.7.tgz",
      "integrity": "sha512-Uo4chgKbnPNlxQwoFmYIwctkQVkMMmsAoGGU4JKwLuvBefF0pCq4FybNSnfkfRCpC7ZW7kttcC/TrRtAJsvGtg==",
      "dev": true
    },
    "@types/schema-utils": {
      "version": "2.4.0",
      "resolved": "https://registry.npmjs.org/@types/schema-utils/-/schema-utils-2.4.0.tgz",
      "integrity": "sha512-454hrj5gz/FXcUE20ygfEiN4DxZ1sprUo0V1gqIqkNZ/CzoEzAZEll2uxMsuyz6BYjiQan4Aa65xbTemfzW9hQ==",
      "dev": true,
      "requires": {
        "schema-utils": "*"
      }
    },
    "@types/source-list-map": {
      "version": "0.1.2",
      "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
@@ -5464,6 +5479,12 @@
      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
      "dev": true
    },
    "json-loader": {
      "version": "0.5.7",
      "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz",
      "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==",
      "dev": true
    },
    "json-parse-better-errors": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
@@ -7468,14 +7489,13 @@
      }
    },
    "schema-utils": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
      "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
      "version": "2.6.4",
      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz",
      "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==",
      "dev": true,
      "requires": {
        "ajv": "^6.1.0",
        "ajv-errors": "^1.0.0",
        "ajv-keywords": "^3.1.0"
        "ajv": "^6.10.2",
        "ajv-keywords": "^3.4.1"
      }
    },
    "semver": {
@@ -8283,6 +8303,17 @@
          "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
          "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
          "dev": true
        },
        "schema-utils": {
          "version": "1.0.0",
          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
          "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
          "dev": true,
          "requires": {
            "ajv": "^6.1.0",
            "ajv-errors": "^1.0.0",
            "ajv-keywords": "^3.1.0"
          }
        }
      }
    },
@@ -8888,6 +8919,17 @@
            "to-regex": "^3.0.2"
          }
        },
        "schema-utils": {
          "version": "1.0.0",
          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
          "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
          "dev": true,
          "requires": {
            "ajv": "^6.1.0",
            "ajv-errors": "^1.0.0",
            "ajv-keywords": "^3.1.0"
          }
        },
        "to-regex-range": {
          "version": "2.1.1",
          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+9 −1
Original line number Diff line number Diff line
@@ -12,14 +12,22 @@
  "keywords": [
    "webpack-plugin",
    "htmlvalidate",
    "javascript"
    "javascript",
    "typescript"
  ],
  "author": "Anthon <anthon.kendel@gmail.com>",
  "license": "MIT",
  "peerDependencies": {
    "json-loader": ">=0.5.7"
  },
  "devDependencies": {
    "@types/json-schema": "^7.0.4",
    "@types/node": "^13.7.7",
    "@types/schema-utils": "^2.4.0",
    "@types/webpack": "^4.41.7",
    "jest": "^25.1.0",
    "json-loader": "^0.5.7",
    "schema-utils": "^2.6.4",
    "standard-version": "^7.1.0",
    "typescript": "^3.8.3",
    "webpack": "^4.41.6",
+4 −11
Original line number Diff line number Diff line
const path = require("path");
const {
  HtmlValidateVueWebpackPlugin
} = require("../../lib/html-validate-vue-webpack-plugin");

module.exports = {
  entry: path.resolve(__dirname, "EButton.vue"),
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: path.resolve(
          __dirname,
          "../../lib/html-validate-vue-webpack-loader.js"
        )
      }
    ]
  }
  plugins: [new HtmlValidateVueWebpackPlugin()]
};
+4 −4
Original line number Diff line number Diff line
import { Configuration } from "webpack";
import htmlValidateVueWebpackLoader from './html-validate-vue-webpack-loader';
import * as path from 'path';

export const htmlValidateVueWebpackConfig: Configuration = {
export const HtmlValidateVueWebpackConfig: Configuration = {
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: htmlValidateVueWebpackLoader,
        loaders: ['json-loader', path.resolve(__dirname, 'html-validate-vue-webpack-loader')],
      }
    ]
  }

};

export default htmlValidateVueWebpackConfig;
 No newline at end of file
export default HtmlValidateVueWebpackConfig;
 No newline at end of file
+44 −10
Original line number Diff line number Diff line
export const htmlValidateVueWebpackLoader = (source: string) => {
  const stringified = source;
  const htmlValidateBlockRegexp = new RegExp(/<htmlvalidate>([\n\t\r]|.)+<\/htmlvalidate>/);
  const htmlValidateBlock = htmlValidateBlockRegexp.exec(source)
  if (htmlValidateBlock) {
    const [first] = htmlValidateBlock;
    const content = first.replace('<htmlvalidate>', '').replace('</htmlvalidate>', '');
    console.info('found the following content:', content);

const toKebabCase = (value: string) => {
  return value.replace(/([A-Z])([A-Z])/g, '$1-$2')
    .replace(/([a-z])([A-Z])/g, '$1-$2')
    .replace(/[\s_]+/g, '-')
    .toLowerCase()
};

export function HtmlValidateVueWebpackLoader(this: any, source: string) {
  const startTag = '<htmlvalidate>';
  const endTag = '</htmlvalidate>';

  const htmlValidateBlockRegexp = new RegExp(`${startTag}([\\n\\t\\r]|.)+${endTag}`);
  const vueComponentNameRegExp = new RegExp(`name:\\s*["']?(\\w+)["']?`);

  const htmlValidateBlock = htmlValidateBlockRegexp.exec(source);
  const componentNameProperty = vueComponentNameRegExp.exec(source);

  try {
    const [htmlValidateBlockFound = '{}'] = htmlValidateBlock ?? [];
    const htmlValidateBlockContent = htmlValidateBlockFound.replace(startTag, '').replace(endTag, '');

    const fullFilePath = this.resource as string;
    const lastIndexOfSlash = fullFilePath.lastIndexOf('/');
    const lastIndexOfDot = fullFilePath.lastIndexOf('.');
    const nameFromFilePath = fullFilePath.slice(lastIndexOfSlash + 1, lastIndexOfDot);

    const [, namePropertyFound = ''] = componentNameProperty ?? [];

    // ? Parse and stringify htmlvalidate block so we know it is a valid JSON.
    const htmlValidateBlockParsed = JSON.parse(htmlValidateBlockContent);
    JSON.stringify(htmlValidateBlockParsed, null, 2);

    const componentName = toKebabCase(namePropertyFound || nameFromFilePath || 'NameNotFound');
    const result = { [componentName]: htmlValidateBlockParsed };
    const resultJson = JSON.stringify(result, null, 2);

    this.emitFile(`${componentName}.json`, resultJson);

    return resultJson;
  } catch (error) {
    console.error('HtmlValidateVueWebpackLoader received the following error:', error);
    return JSON.stringify({});
  }
  return '';
}

export default htmlValidateVueWebpackLoader;
 No newline at end of file
export default HtmlValidateVueWebpackLoader;
 No newline at end of file
Loading